Why errors on borrowing mutably more than once

Hi,

I have updated the "Cacher" exercise from chapter 13.1 of "The Book of Rust". In my attempts to make it work I first was returning references to values from the HashMap... and I got compilation errors in my tests that I cannot mutably borrow more than once.
Those errors went away when I was no longer returning references.

I have since noticed that I get those errors only when repeatedly trying to get the same value from the "Cacher" ... Which I can see makes sense.
However, I also get the error on lines that retrieve a different value, when it's in the same function that tries to retrieve same value twice.

Can anyone please help me to understand the errors?

Without copy-pasting the full code, for brevity:

    #[test]
    fn test_with_returning_refs_3x_1() {
        let mut c = Cacher::new(|a| a);

        let v1 = c.value_ref(1);
        let v2 = c.value_ref(2); // <-- Error here which I don't get
        let v3 = c.value_ref(1); // <-- Error here which I can understand but didn't expect at first. No error if I remove this line.

        assert_eq!(v2, &2);
    }

Error:

error[E0499]: cannot borrow `c` as mutable more than once at a time

Cacher implemented as follows:

struct Cacher<F, V, R>
    where F: Fn(V) -> R
{
    calculation: F,
    values: HashMap<V, R>,
}

impl<F, V, R> Cacher<F, V, R> where
    F: Fn(V) -> R,
    V: std::marker::Copy + std::cmp::Eq + Hash,
    R: std::marker::Copy,
{
    fn new(calculation: F) -> Cacher<F, V, R> {
        Cacher {
            calculation,
            values: HashMap::new(),
        }
    }

    fn value_ref(&mut self, arg: V) -> &R {
        if !self.values.contains_key(&arg) {
            let result = (self.calculation)(arg);
            self.values.insert(arg, result);
        }
        return &self.values[&arg]
    }
}

The Cacher is borrowed mutably until the reference value_ref returns is no longer used since the function takes &mut self. Without the v3 line, the reason it works is that v1 is not used after creating v2, so the compiler decides to end the borrow before creating v2 instead of at the end of the scope. When you add v3, the compiler notices that the v2 borrow cannot end before creating v3 due to v2 being used in the assert after creating v3.

The rule you're violating is that mutable references are not allowed to overlap with any other reference in the program, except those the mutable reference was created from.

2 Likes

Thanks, that makes sense to me now!

This wasn't clear to me from the error message.

That's basically the same problem I had some time ago. It all boils down to &mut coercing into & and the compiler still treating & as &mut, even if you don't need/want it to be &mut, anymore. My answer to my question includes a minimal example to reproduce the error you got.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.