0

Consider these two code examples

struct A {
    v: Vec<usize>,
    a: usize,
}

impl A {
    fn f(&mut self) {
        for _ in self.v.iter_mut() {
            self.f_mut();
        }
    }

    fn f_mut(&mut self) {
        self.a += 1;
    }
}

which produces the compile error

error[E0499]: cannot borrow `*self` as mutable more than once at a time
 --> src/binaries/main.rs:9:13
  |
8 |         for _ in self.v.iter_mut() {
  |                  -----------------
  |                  |
  |                  first mutable borrow occurs here
  |                  first borrow later used here
9 |             self.f_mut();
  |             ^^^^ second mutable borrow occurs here

error: aborting due to previous error

whereas this code

struct A {
    v: Vec<usize>,
    a: usize,
}

impl A {
    fn f(&mut self) {
        for _ in self.v.iter_mut() {
            self.a += 1;
        }
    }

    fn f_mut(&mut self) {
        self.a += 1;
    }
}

compiles just fine. Obviously these two pieces of code have identical behaviour so I am wondering if there is some way to get Rust to accept the first solution?

In my project I have some quite large for loops which I would like to refactor by splitting the body of the for-loop into separate function calls, but Rust doesn't allow me to do it.

That is, my more complicated code structured as example 2 compiles fine, but refactored into easier digestable functions as example 1 gives me the cannot borrow *self as mutable more than once at a time error.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • An aside, but are you sure you don't just want `self.a += self.v.len()`? Or at the very least, as you don't modify the contents of the vector, `for _ in self.v.iter() { ... }`? – Chris Jun 07 '22 at 18:01
  • 1
    Does this answer your question? [How to borrow two disjoint fields when the borrow is behind a method call?](https://stackoverflow.com/questions/67154204/how-to-borrow-two-disjoint-fields-when-the-borrow-is-behind-a-method-call), [Rust not allowing mutable borrow when splitting properly](https://stackoverflow.com/questions/61699010/rust-not-allowing-mutable-borrow-when-splitting-properly) – John Kugelman Jun 07 '22 at 18:01

1 Answers1

4

Your second example works because it performs a splitting borrow. The compiler can see that you're only borrowing self.v mutably, so it lets you borrow other fields on self mutably as well, since they don't overlap.

However, in the first example, self.f_mut() requires borrowing all of *self mutably (because it takes &mut self), which overlaps with the borrow of self.v, and is therefore disallowed. This requires borrowing the whole value because the borrow checker only uses the signature of the called function -- it does not look into the function to see that it doesn't use self.v. (If it did look into functions, then changing the body of a function without changing its signature could be an API-breaking change!)

Simply put, a function call is a "hard" boundary for the borrow checker. By using a function call in the first example, the detail that only self.a is used is hidden from the borrow checker.

cdhowie
  • 158,093
  • 24
  • 286
  • 300