Search code examples
rusthashmapownership

Returning a &HashMap from rust function


I am struggling to find an elegant to solution to access a nested map for read-only purposes in rust. I have a situation of this kind and ideally as example I could return a reference to an empty map (that of course doesn't work since the empty hashmap is owned by the function):

struct S {
    stuff: HashMap<A, HashMap<B, C>>
}

impl S {
    fn get(&self, a: &A) -> &HashMap<B,C> {
        return self.stuff.get(a).unwrap_or(&HashMap::new());
    }
}

There is no guarantee that the map stuff will have the key a, hence handling optionality is a must.

I would like the solution to implement the method get with this or similar signature in an efficient way (no copies/moving) because the map stuff can be quite big.

I could only think of the following solutions, but I am thinking there must be a more straightforward one:

  1. Add a private field in struct S that is just an empty HashMap so that I can return a reference of. This seems a bad lazy solution.
  2. Call entry(a).insert_with(|| HashMap::new()), but this requires unnecessary mutability.
  3. Return Option<&HashMap>

It seems to me that the solution (3) is the best way to achieve the above, but maybe I am missing something and there is a more straightforward way?


Solution

  • Returning Option<&HashMap> is idiomatic and simple.

    fn get(&self, a: &A) -> Option<&HashMap<B,C>> {
        self.stuff.get(a)
    }
    

    Anything you might do with &HashMap can be done with Option<&HashMap>. For instance, you can check if a key is present.

    if s.get(&a).map_or(false, |hm| hm.contains_key(&b)) {
        println!("key exists");
    }
    

    This produces false when get returns None, which is the same as if you call contains_key on an empty HashMap.

    As a bonus, an Option containing a reference is always the same size in memory as just the reference.