Why they behave differently?

In the following code , it's ok to take 2 mutable references of 2 non overlapped fields at the same time

fn main() {
  struct U(u8,u8);
  let mut u = U(0,0);
  let x = &mut u.0;
  let y = &mut u.1;
  *x=1;
  *y=1;
}

when trying to encapsulate in methods , the behavior changed. So what makes the difference?

fn main() {
  struct U(u8,u8);  
  let mut u = U(0,0);
  let x = u.get0();
  let y = u.get1();
  *x=1;                   // can't compile
  *y=1;
  
  impl U {
    fn get0(&mut self)->&mut u8 {
      &mut self.0
    }

    fn get1(&mut self)->&mut u8 {
      &mut self.1
    }
  }
}

The compiler is only smart enough to "split borrows" within a single scope. The function get0 compiles on its own and the prototype says it borrows the whole of self. Then the borrow checker fails compiling main because all of self is borrowed by get0 so calling get1 isn't allowed.

As far as strategies to get around this, it depends on your situation. Sometimes it's just a code refactor you need. Sometimes you should use "setter" calls, rather than "get_mut" calls. Sometimes you need internal mutability.

Slices / Iterators have some tricks up their sleeve that you might be able to replicate. Splitting Borrows - The Rustonomicon

thanks for give the reference materials. :slightly_smiling_face:

Another possibility here is to add

  impl U {
    fn get0_and_1(&mut self)->(&mut u8, &mut u8) {
      (&mut self.0, &mut self.1)
    }
  }

But note that in Rust it's relatively rare to offer &mut accessors to fields because the amount of refactoring protection they offer is limited -- the reference needs to refer to something inside the struct, so it can't be something dynamically computed.

Generally, if you're willing to give a &mut to a field -- meaning it can't maintain any invariants, since the caller can make whatever change they want -- then you should consider just making it pub and letting the caller use it directly. That way the compiler knows it's a field, it can do all the borrow-splitting goodness.

4 Likes

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.