HashMap<&str,Foo> vs HashMap<String,Foo>


#1

Hello all.

I have a struct which, among other things, owns a string called name. I have another struct which stores a hashmap of the previous struct. Something like:

struct Foo { name: String }
struct FooMgr { foos: HashMap<String, Foo> }

While this works, it involves additional cloning of Foo.name to act as a key in the hashmap.

What I really want is something like:

struct FooMgr { foos: HashMap<&str ,Foo> }

But I am stuck on how to deal with the lifetime for the &str in my add_foo method, since I want to associate it with Foo and not FooMgr. Can someone point me at an example or docs which would be relevant?


#2

In short, what you’re attempting to do will create a self-referential struct.

To side step this, you can share the ownership of the string between the HashMap and the Foo:

struct Foo { name: Rc<str> }
struct FooMgr { foos: HashMap<Rc<str>, Foo> }

If you just want to look up the Foos by name, consider using a HashSet<Foo>, which you can query via HashSet::get. This method allows you to pass something that Foo can be borrowed as, so if you make it impl Borrow<str> for example, you can look them up by string slices.


#3

Thanks vitalyd. I actually went down that road initially. Unfortunately, I hit an issue with my inability to call contains_key with a &str:
playground example


#4

Yes, I remember this has bitten me as well, but as @vitalyd said, the trick is to use Rc<str>.

You can do it like this: https://play.rust-lang.org/?gist=f4e72644a290a6d8fa1dac00b65d3d2c&version=stable


#5

Separately but relatedly, it seems like an omission that Rc<String> doesn’t impl Borrow<str>.


#6

Vitalyd, birkenfeld, thank you both!