0

I have some objects that are constructed, stored in a single data structure, and updated during a run of my binary. Sometimes they get lonely and need friends, so they need to be able to search through the storage, locate a friend, remember the friend's identity, and tell the friend who they are.

struct Obj {
    id: i32,
    friend: Option<i32>,
}

impl Obj {
    fn find_friend(&mut self, storage: &mut HashMap<i32, Obj>) {
        // let's pretend we found this friend in storage
        let friend_id = 1;
        let new_friend = storage.get_mut(&friend_id).unwrap();
        self.friend = Some(new_friend.id);
        new_friend.friend = Some(self.id);
    }
}

fn main() {
    let mut storage: HashMap<i32, Obj> = HashMap::new();
    let obj = Obj {
        id: 0,
        friend: None,
    };
    let id = obj.id;
    storage.insert(id, obj);

    // time passes
    let obj_again = storage.get_mut(&id).unwrap();
    obj_again.find_friend(&mut storage);
}

Unfortunately I get in fights with the borrow checker:

error[E0499]: cannot borrow `storage` as mutable more than once at a time
   --> src\main.rs:190:22
    |
189 |   let obj_again = storage.get_mut(&id).unwrap();
    |           ------- first mutable borrow occurs here
190 |   obj_again.find_friend(&mut storage);
    |                      ^^^^^^^ second mutable borrow occurs here
191 | }
    | - first borrow ends here

error: aborting due to previous error

How can I structure this code such that I can fetch a reference to an object out of storage and then allow it to mutate itself, its compatriots, and the data structure that contains them?

Edit: I'm not sure that this is a duplicate of the question "How do I get two mutable references into a container?" This is "How can an object inside a container mutate itself if it also needs to be able to mutate its container?". Sorry if that wasn't clear.

user2981708
  • 167
  • 1
  • 2
  • 7
  • Crucially the answer to the question marked as duplicate relies on runtime borrow checking to enforce the fact that the two values borrowed from INSIDE the container are different. The issue here is that the current structure forces a mutable borrow of the container itself after it has already been borrowed to retrieve the stored object. – user2981708 Feb 14 '19 at 16:50
  • 1
    I've added additional duplicates that talk more about why what you want to do cannot be safe, such as [this specific answer](https://stackoverflow.com/a/52857223/155423). *the current structure forces a mutable borrow of the container itself* — yes, which you then attempt to use to get a second value (`storage.get_mut(&friend_id)`). You cannot have a mutable reference to the container and a value in the container at the same time because the former would allow you to invalidate the latter (e.g. via `storage.clear()`). This cannot be checked at compile time, but only at runtime. – Shepmaster Feb 14 '19 at 19:39
  • 1
    [The duplicates applied to your specific case](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4ed231b5262850314af9b29ef4c77465). – Shepmaster Feb 14 '19 at 19:42
  • These were very helpful, thank you. – user2981708 Feb 15 '19 at 04:29

0 Answers0