Is it possible to insert a struct into a map where the key is owned by the value being inserted?
When using hash-maps in C, this is something which I'm used to doing.
Pseudocode example:
struct MyStruct {
pub map: BTreeMap<&String, StructThatContainsString>,
// XXX ^ Rust wants lifetime specified here!
}
struct StructThatContainsString {
id: String,
other_data: u32,
}
fn my_fn() {
let ms = MyStruct { map: BTreeMap::new() };
let item = StructThatContainsString {
id: "Some Key".to_string(),
other_data: 0,
}
ms.insert(&item.id, item);
}
How can this situation be correctly handled?
If this isn't possible, could the reverse be done, where the value holds a reference to the key which would be a
String
?An alternative could be to use a
set
instead of amap
, then store the entirestruct
as the key, but only use one of its values when comparing (seems like it would work, but could backfire if you wanted to compare thestruct
in other contexts).
Using a single member of a struct as a key in a map can be done (in principle) by using a set with a zero-overhead wrapper struct that only serves to override implementations.
Ord, Eq, PartialEq, PartialOrd
To control it's order in the set.
Override
Borrow
soBTreeSet.get(..)
can take the type used for ordering, instead of the entire struct.One down side with this method is you need to wrap the struct with the container when adding it into the set.
Here is a working example:
To avoid having to define these manually, this can be wrapped up into a macro:
It's not going to work with plain references:
item
is moved into the map, so there can't be any pending borrows/references.Also, methods like
get_mut()
would become dangerous or impossible, as it would let you modify the item that has an outstanding reference.Assuming the reason for wanting to do this is to save space, the obvious options are:
Take the key out of the value struct. If you need it at the same time, you've either got it when looking up a key in the map, or the iterators include both key and value.
Use something like
Rc
for the key part of the value.Rc<T>
implementsOrd
(required forBTreeMap
) ifT
does.