Trying to understand mutable and immutable references

Hey there,

As I understand it, it is possible to have an immutable reference and a mutable one as long as the lifetime of the immutable one is gone by the time you declare the mutable.

In the code bellow the first method compiles while the second one doesn't, both with an immutable and a mutable reference, I thought the lifetime of the immutable reference would end with the loop but that doesn't seem to be the case, so what's really going on here ?

#![allow(dead_code)]

use std::collections::HashMap;
use std::hash::Hash;
use std::borrow::Borrow;

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

impl Test {
    fn print_and_remove<Q>(&mut self, key: &Q)
    where
        String: Borrow<Q>,
        Q: Eq + Hash + ?Sized,
    {
        match self.map.get(key) {
            Some(v) => println!("{v}"),
            None => {
                println!("Not found");
                return;
            }
        };
        
        self.map.remove(key);
    }
    fn remove_by_value(&mut self, value: &String) {
        let mut keys = Vec::new();
        
        for (k, v) in self.map.iter() {
            if v == value {
                keys.push(k);
            }
        }
        
        for key in keys {
            self.map.remove(key);
        }
    }
}

The compiler message:

Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `self.map` as mutable because it is also borrowed as immutable
  --> src/lib.rs:37:13
   |
30 |         for (k, v) in self.map.iter() {
   |                       --------------- immutable borrow occurs here
...
36 |         for key in keys {
   |                    ---- immutable borrow later used here
37 |             self.map.remove(key);
   |             ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error

It can't end there, because you collected the references into keys.

I would use retain for this code, but maybe your real code is more complicated...

1 Like

In the second method, you are storing references to the keys, and you are trying to use them for removal, so there are outstanding immutable borrows into the map while you are attempting the removal (which requires a mutable borrow).

1 Like

Oh ! I see now ! And thanks for the suggestion, retain will work !

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.