Maps, objects and lifetimes


#1

I want to insert in a struct
HashMap<&str, MyStruct>
where

struct MyStruct{
  name: String
//other fields
}

And I would like to use as key of the map a pointer to the name field of the struct. Theoretically the lifetime should be ok (the string lives as long as the struct that lives as long as the map entry), but I don’t know how to tell this to Rust.
Thank you for your help

Edit: More precisely, in my case, I have a HashMap<&str, Arc<MyStruct>>


Share String between key and value of HashMap
#2

I don’t think this is true unfortunately. For example consider the following hypothetical code. Maybe this is Rust preventing a legitimate bug that you would have spent hours debugging later?

use std::collections::HashMap;

struct MyStruct {
    name: String,
    // other fields
}

fn main() {
    let garro = MyStruct {
        name: "garro".to_owned(),
    };

    let mut map = HashMap::new();
    map.insert(&garro.name, garro);

    // This drops the original "garro" String so the map key refers
    // to freed memory.
    map.get_mut("garro").unwrap().name = "not garro".to_owned();
}

#3

You could write a wrapper type, like struct MyStructEntry(Arc<MyStruct>), and implement Hash, Eq, and Borrow<str> as simple pass-throughs to name. Then you can use a HashSet instead of a map and still lookup entries with &str keys.


#4

Looks like HashSet::get is still marked unstable though? Might be a wrinkle for someone using stable.


#5

I don’t think so – here it’s marked stable since 1.9.0.


#6

Yikes, I was looking at old docs (not the first time this has happened :frowning:).


#7

Yes, that’s right. Even if I don’t do anything similar anywhere in the code Rust can’t prove it. Thank you!

Thank you for your tip, but to be honest, I don’t like this solution very much (and I don’t know why*). Anyway I’ll try it.

In my first solution I was using a String as key of the map and cloning the string to have a copy in the struct and a copy in the map “keyset”, but then I found it was a waste of memory, that’s why I thought to use the same string that I have in the struct.
I think I will also try to avoid using the string inside the struct (i.e. use the string only as key of the map).
Any suggestions or critiques are appreciated! Thank you again


#8

If it’s acceptable for you to keep the name separate, then yes, that’s probably easier. It also gives you the possibility to still mutate other parts of the struct. (set values and map keys are immutable, but map values are not.)


#9

OK, I thought I can use another solution based on indexing.
I would have a data structure that holds all the strings and associate them to ascending integers (let’s say usize) which can be used to index in a vector.
This would solve a lot of problems since the part that really needs the strings is the user interface and that would have the ownership of the strings, while the usize's, that are Copy could be passed everywhere.
For the data structure I thought I could use a HashMap to associate the Strings to the integers and perform the translation, although I remember that I have seen a crate that do exactly what I want.
Does anybody know what’s the name of the crate I’m talking of?
Thank you again