HashMap / HashSet 'get_key()', generalised contianer


#1

I would like to store values in some container indexed by a sub-property; i.e. I wish to store structs where one of the fields contains the key.

struct MyData {
    key: K,
    ...
}

Possibilities:

  1. Use HashMap<K, MyData> and just store the key twice.
  2. Remove key from MyData — but there are reasons MyData wants to know about the key
  3. Define struct MyDataExceptKey and use in the HashMap, then recreate MyData when extracting… but this is really silly.
  4. Use HashSet<MyData> and special implementations of PartialEq and Hash which only compare based on MyData's key. (This means values in the set are immutable, which is okay for my use case.) [I’ve used this option with C++'s std::set/map before.]

The last option is the route I’ve gone, except that I’ve created a wrapper library so that the user’s type doesn’t itself have to have modified eq and hash implementations. (I was planning on releasing the library when it’s working.)

Problem: neither HashSet nor HashMap provides a way to get the key (except by iterating). Can this be changed?

As an aside, my wrapper API could almost be used as a generalisation of HashMap and HashSet; the exception being that values couldn’t be modified in place without a run-time check that the key didn’t change (and in any case, this isn’t possible when building on top of HashSet or HashMap).


#2

There was an RFC to cover this use case but it looks like the author didn’t have the free time to keep it updated: https://github.com/rust-lang/rfcs/pull/1175. Key access seems like reasonable functionality to have - we just have to iron out the details. If you’re feeling motivated, please feel free to revive that RFC!


#3

This is actually deferred functionality from RFC 1194.

EDIT: FYI BTreeSet and HashSet do expose their keys:


#4

@apasel422, those additions would suit me nicely (though it’s a shame the existing remove function can’t have its return type updated).

What’s the status? Looks like it’s in nightly but it’s still marked unstable?


#5

Yes, it hasn’t yet been stabilized. Unfortunately, remove's return type can’t be updated without breaking backwards compatibility.


#6

@apasel422: RFC 1194 was merged. #28043 was merged. So why is this still unstable and #28050 still open? Is there a cooling off period or still implementation work to be done, or are there still decisions to be made (e.g. about the previous RFC)?


#7

As far as I know, it’s just that no one has pushed to stabilize it, and theoretically the implementation could still change to use different names if someone comes up with some.


#8

Well, now there’s a crate relying on this: HashIndexed.