Beginner question: borrow checker issue

Hi,

I am new to Rust and experience some issue understanding the borrow checker in the following code.

Why does the following code work for the NonMutstruct and fails to compile for Mut?
The only difference between the 2 is the mutability of v.

I would be tempted to think that the 2 approaches should fail the same way but for NonMut, it seems that I am allowed to borrow *self mutably while it was borrowed immutably by the loop (?!?).

Thank you very much in advance for your help.

Happy coding,

Ramses

#![allow(dead_code)]

pub struct Mut<'a> {
    v: &'a mut Vec<u8>,
}

impl<'a> Mut<'a> {
    fn foo(&mut self) {
        for _ in self.v.iter() {
            self.bar();
        }
    }
    fn bar(&mut self) {}
}

pub struct NonMut<'a> {
    v: &'a Vec<u8>,
}

impl<'a> NonMut<'a> {
    fn foo(&mut self) {
        for _ in self.v.iter() {
            self.bar();
        }
    }
    fn bar(&mut self) {}
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/lib.rs:10:13
   |
9  |         for _ in self.v.iter() {
   |                  -------------
   |                  |
   |                  immutable borrow occurs here
   |                  immutable borrow later used here
10 |             self.bar();
   |             ^^^^^^^^^^ mutable borrow occurs here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0502`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

The NonMut version works because immutable (&T) references are Copy, so self.v can create a new reference that is independent of self and guaranteed to remain valid even if self is mutated.

An &mut T reference is not Copy and must have exclusive access to its referent. Since these references can’t be copied, self.v.iter() can only borrow the v field, not copy it. And then passing &mut self to another method while an iterator is borrowing self.v would violate the rule of exclusivity.

3 Likes

Wow. Thank you for the quick answer!

I didn’t think about Copy to explain this behavior. Now I am wondering when those (implicit?) copies are being made. Are Copy items systematically being copied? Or is this a fallback mechanism?

Whether any copying actually takes place usually depends on the optimizer.

Things implementing Copy imply that copying of them is safe and cheap, so you shouldn’t need to worry about it.

Note that only the reference gets copied, not the data behind it.

1 Like