Cannot borrow `*self` as mutable more than once at a time...for the nth time...I know

Even with the compiler outlining it, I don't understand where the "more than once" borrow of *self happens. in bar and much less how to avoid it, while keeping the overall idea (which inlining baz for exaple wouldn't be).

Can someone please dumb it down for me?

struct Fuzz {
    val: i32,
}

struct Foo {
    arr1: Vec<Fuzz>,
    something_else: i32,
}

impl Foo {
    fn bar(&mut self) {
        let f: &mut Fuzz = &mut self.arr1[0];
        self.baz(f);
    }

    fn baz(&mut self, f: &mut Fuzz) {
        self.something_else = 11;
        f.val = 12;
    }
}

fn main() {
    let mut foo = Foo {
        arr1: vec![Fuzz { val: 42 }],
        something_else: 10,
    };

    foo.bar();
}

the most common solution is to use an index instead of a direct reference if possible:

    fn baz(&mut self, f: usize) {
        self.something_else = 11;
        self.arr1[f].val = 12;
    }
1 Like

The code is nice, but the error message (or playground link) would also be helpful:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:13:9
   |
12 |         let f: &mut Fuzz = &mut self.arr1[0];
   |                                 --------- first mutable borrow occurs here
13 |         self.baz(f);
   |         ^^^^     - first borrow later used here
   |         |
   |         second mutable borrow occurs here

The error message gives you precise locations of where borrows occur (note that sometimes it is less than perfect, but it's amazing that it's as capable as it is).

To analyze the error message, we need to be aware that line 12 exclusively borrows a field on self, which the message indicates with an underline. And on line 13, all of self is borrowed by the method call. This "borrow all of self" happens because the method signature of baz tells us it is so:

fn baz(&mut self, f: &mut Fuzz)

The method receives &mut self (it would have the same problem if it was &self) which says, "all of self is borrowed".

This should make it clear why there is an error. A single field on self is borrowed for exclusive access, and then all of self is simultaneously borrowed. That violates the "Shared Xor Mutable" principle.

This specific issue is generally known as "partial borrows" and a lot has been written about it. This is probably the best resource that describes the cause of the problem, and some workarounds that exist today for it: After NLL: Interprocedural conflicts · baby steps and this one has some ideas on how it might be addressed at the language level: View types for Rust · baby steps

6 Likes

Thank you for the links! Glad to see that I've found 2.5 of the 4 described ways on my own (the .5 because I was still working on the "factoring" way). And that I'm not alone in my frustration...

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.