Search code examples
rustborrow-checkerborrowing

How does multiple mutable reference prevention work in Rust?


Why it is allowed to do something like this:

fn main() {
    let mut w = MyStruct;
    w.fun1();
}

struct MyStruct;

impl MyStruct {
    fn fun1(&mut self) {
        self.fun2();
    }

    fn fun2(&mut self) {
        println!("Hello world 2");
    }
}

In the above code fun1() gets mut MyStruct and calls fun2() also with mut MyStruct. Is it double mutable reference in one scope?


Solution

  • This is allowed because the borrow checker can conclude there is only one mutable reference being accessed during execution. While fun2 is running, no other statement in fun1 is being executed. When the next statement in fun1 (if there was any) starts executing, fun2 has already dropped its mutable reference.

    In the other question linked:

    fn main() {
        let mut x1 = String::from("hello");
        let r1 = &mut x1;
        let r2 = &mut x1;
    
        r1.insert(0, 'w');
    }
    

    We can say r2 is never used, but borrow checker decided it shouldn't be allowed. Consider this example:

    fn main() {
        let mut x1 = String::from("hello");
        let r1 = &mut x1;
        r1.insert(0, 'w');
    
        let r2 = &mut x1;
        r2.insert(0, 'x');
    }
    

    This compiles and runs correctly. I suppose borrow checker assumes the lifetime r1 ends before r2 is created. If this makes sense, calling methods that mutate self shouldn't be so surprising.

    (I don't know why the 1st piece of code does not compile, but I am glad rust team made it that way. r2 should not be there anyway.)