0

I am trying to create a struct, which contains a hashmap and a vector, thereby the vector should contain references to values from the hashmap.

I thought that multiple mutable borrows on the same instance are possible, when put into independent scopes.

(Playground)

use std::collections::HashMap;

struct Container<'a> {
    map: HashMap<String, String>,
    vec: Vec<&'a String>
}

impl<'a> Container<'a> {
    pub fn new() -> Self {
        Container {
            map: HashMap::new(),
            vec: Vec::new()
        }
    }

    pub fn add_link(&'a mut self, key: &str) {
        if let Some(value) = self.map.get(key) {
            self.vec.push(value);
        }
    }

    pub fn print_vec(&self) {
        println!("Vec: {:?}", self.vec);
    }
}

fn main() {
    let mut container = Container::new();

    {
        container.map.insert("a".to_string(), "x".to_string());
    }
    {
        container.map.insert("b".to_string(), "y".to_string());
    }
    {
        container.map.insert("c".to_string(), "z".to_string());
    }

    {
        container.add_link("c");
    }
    {
        container.add_link("a");
    }
    {
        container.add_link("c");
    }
    {
        container.add_link("k");
    }

    container.print_vec();
}
error[E0499]: cannot borrow `container` as mutable more than once at a time
  --> src/main.rs:44:9
   |
41 |         container.add_link("c");
   |         --------- first mutable borrow occurs here
...
44 |         container.add_link("a");
   |         ^^^^^^^^^
   |         |
   |         second mutable borrow occurs here
   |         first borrow later used here


(...)

I am expecting the output to be: Vec: ["z", "x", "z"]

zingi
  • 1,141
  • 13
  • 23
  • I am reading this answer but I don't quite understand what I have to change in my code to make it work. – zingi Apr 12 '20 at 09:52
  • 2
    There's no easy answer. What you're trying to do is not a simple problem (for example, what happens if the `HashMap` has to reallocate? As written, this would invalidate all the references in the vector, which is not good). Read the answers at the linked question very closely and then make a decision. – SCappella Apr 12 '20 at 09:58

1 Answers1

0

tl;dr

It is not (yet 1.41.1) trivial to implement self referencing structs.

Like @SCappella mentioned, there is already a more detailed approach to this problem here.


My approach to solve the problem is to bypass the original problem with splitting my container struct up in two separate structs, where the referencing struct is apart from the data-owning struct.

(Playground)

use std::collections::HashMap;

struct Container {
    map: HashMap<String, String>,
}

struct DependentContainer<'a> {
    vec: Vec<&'a String>,
}

impl Container {
    pub fn new() -> Self {
        Container {
            map: HashMap::new(),
        }
    }

    pub fn add(&mut self, key: &str, value: &str) {
        self.map.insert(key.to_string(), value.to_string());
    }
}

impl<'a> DependentContainer<'a> {
    pub fn new() -> Self {
        DependentContainer {
            vec: Vec::new()
        }
    }

    pub fn add_link(&mut self, container: &'a Container, key: &str) {
        if let Some(value)= container.map.get(key) {
            self.vec.push(value);
        }
    }

    pub fn print_vec(&self) {
        println!("Vec: {:?}", self.vec);
    }
}

fn main() {
    let mut container = Container::new();
    let mut dep_container = DependentContainer::new();

    container.add("a", "x");
    container.add("b", "y");
    container.add("c", "z");

    dep_container.add_link(&container, "c");
    dep_container.add_link(&container, "a");
    dep_container.add_link(&container, "c");
    dep_container.add_link(&container, "k");

    dep_container.print_vec();
}
zingi
  • 1,141
  • 13
  • 23