1
struct C {
    p: String,
    q: String,
}

impl C {
    fn call(&mut self) {}
}

fn main(){
    let mut c = C { p: "p".to_string(), q: "q".to_string() };        
    let p = &mut c.p; // first mutable borrow occurs here
    let q = &mut c.q; // second mutable borrow doesn't occur here, why???
    c.call();         // second mutable borrow occurs here  // error[E0499]: cannot borrow `c` as mutable more than once at a time
    p.push('x');
    q.push('y');
}

let q = &mut c.q; second mutable borrow doesn't occur here, why??? I really can't figure it out, can someone explain why in depth?

cafce25
  • 15,907
  • 4
  • 25
  • 31
wangliqiu
  • 369
  • 1
  • 9

1 Answers1

5

let q = &mut c.q; second mutable borrow doesn't occur here, why???

Because the compiler is smart enough to know that there isn't a mutable reference to c.q. There is one to c.p, but not to c or c.q. That is called a split borrow: fields of a structure can be independently mutably borrowed.

Note:

  • this only works intra-procedurally, split borrows don't exist at the type system level
  • this will work with closures in rust 2021, thanks to disjoint closure capture
  • it may not work when involving smart pointers, for instance if c is a MutexGuard, split borrowing doesn't work, whereas a Box does

Fundamentally this is just a convenience, you could use pattern matching to hand-roll the split:

// assuming c is a smart pointer (box, mutexguard, ...)
// remove deref' for a plain C
let C { p, q } = &mut *c;
Masklinn
  • 34,759
  • 3
  • 38
  • 57
Jonas Fassbender
  • 2,371
  • 1
  • 3
  • 19