Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create hashmap containing reference to another hashmap's element?

Tags:

rust

I'm trying to make a struct containing two hashmaps - one with some value, and one with reference to another hashmap's element. Here is my code.

use std::collections::HashMap;

struct Foo;
struct Bar<'s>(&'s Foo);

struct MyStruct<'a> {
    first : HashMap<&'a str, Foo>,
    second : HashMap<&'a str, Bar<'a>>,
}

impl<'a> MyStruct<'a> {
    fn new() -> MyStruct<'a> {
        let mut result = MyStruct {
            first : HashMap::new(),
            second : HashMap::new(),
        };
        match result.first.get("") {
            Some(t) => { result.second.insert("", Bar(t)); },
            None => {},
        }
        result
    }
}

fn main() {
}

and this code fails to compile with following error :

error: result.first does not live long enough

I think this problem is related to lifetime, but I can't clearly explain what is wrong.

Could anybody explain what is happening and how to solve this error?

P.S. struct Foo and Bar are from library, so I can't modify these structs.

like image 215
Remagpie Avatar asked Sep 27 '22 22:09

Remagpie


1 Answers

The problem is indeed related to ownership/borrowing/lifetimes.

In general, in Rust, it is not possibly to (safely) take a reference in a sibling attribute; therefore having .second point into .first is impossible.

However, even if you separated this in two structures, you will still run into problems because taking a reference into a HashMap borrows it (which means that as long as the reference lives, modifying the HashMap is forbidden), which is probably not what you wish for.

This last hurdle can be avoided, in this case, by simply sharing the memory; for example, having both HashMap using a Rc<X> value instead of X and &'a X respectively...

... however this will not help with your particular question given the Foo and Bar<'a> types.

You could change your structure into:

struct MyStruct<'a, 'b> {
    first: HashMap<&'a str, &'b Foo>,
    second: HashMap<&'a str, Bar<'b>>,
}

and then maintain the actual Foo instances elsewhere. A possibility if you need to allocate those Foo while maintaining the HashMap is to use arena allocation such as Arena<Foo>.

like image 133
Matthieu M. Avatar answered Oct 11 '22 16:10

Matthieu M.