为什么 Rust 在已经持有可变借用的情况下再次尝试借用 *self 作为可变借用?

Why does Rust try to borrow *self as mutable again, when it already holds a mutable borrow?

为什么下面的程序会产生如下错误?有什么办法可以在不改变程序流程的情况下修复错误吗?

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:10:39
   |
9  |         for bar in &mut self.bars {
   |                    --------------
   |                    |
   |                    first mutable borrow occurs here
   |                    first borrow later used here
10 |             bar.add_foo_value_and_inc(self);
   |                                       ^^^^ second mutable borrow occurs here

程序:

#[derive(Debug)]
struct Foo {
    add_value: u32,
    bars: Vec<Bar>,
}

impl Foo {
    fn add_value_to_bars(&mut self) {
        for bar in &mut self.bars {
            bar.add_foo_value_and_inc(self);
        }
    }
}

#[derive(Debug)]
struct Bar {
    value: u32,
}

impl Bar {
    fn add_foo_value_and_inc(&mut self, foo: &mut Foo) {
        self.value += foo.add_value;
        foo.add_value += 1;
    }
}

fn main() {
    let mut foo = Foo{add_value: 1, bars: vec![Bar{value:2}, Bar{value:3}]};
    foo.add_value_to_bars();
}

在我看来,函数 add_value_to_bars 已经持有对 self 的可变引用(这是函数的参数)。那么,为什么它在调用 bar.add_foo_value_and_inc 时再次尝试借用 self 作为可变

注意:这是一个用于重现问题的最小程序,因此它不是明智的。

编辑:@Herohtar 评论说“add_foo_value_and_inc 试图可变地借用 self 而 add_value_to_bars 已经拥有一个可变引用,因此它被第二次借用。"

如果是这个原因,那么为什么下面的代码编译 运行 没有任何问题?

函数 add_three 已经持有对 x 的可变引用。函数 add_two 接受一个可变的 再次参考 x 但在这种情况下不会造成任何问题

fn main() {
    let mut x: u32 = 1234;
    add_three(&mut x);
}

fn add_three(x: &mut u32) {
    add_two(x);
    add_one(x);
}

fn add_two(x: &mut u32) {
    *x += 2;
}

fn add_one(x: &mut u32) {
    *x += 1;
}

这是 Rust 在做 Rust 的设计目的:防止您以不安全的方式使用内存。

self.bars 的可变引用被借用并赋予 implicitly-created std::slice::IterMut 值(循环正在使用的迭代器)。因此,self 不能在循环内可变地借用——它包含已经借用的 self.bars

如果 Rust 允许这种情况发生,将会有两个 concurrently-existing 可变引用,通过它们 self.bars 可以被改变,这就是 正是 借用的东西检查器旨在防止。

但是有一个解决方案:您可以可以在循环中借用self不同部分。如果您将 Bar::add_foo_value_and_inc 更改为接受 &mut u32 而不是 &mut Foo,那么您可以借用 self.add_value,这是此方法修改的唯一字段。

#[derive(Debug)]
struct Foo {
    add_value: u32,
    bars: Vec<Bar>,
}

impl Foo {
    fn add_value_to_bars(&mut self) {
        for bar in &mut self.bars {
            bar.add_foo_value_and_inc(&mut self.add_value);
        }
    }
}

#[derive(Debug)]
struct Bar {
    value: u32,
}

impl Bar {
    fn add_foo_value_and_inc(&mut self, foo_value: &mut u32) {
        self.value += *foo_value;
        *foo_value += 1;
    }
}

fn main() {
    let mut foo = Foo{add_value: 1, bars: vec![Bar{value:2}, Bar{value:3}]};
    foo.add_value_to_bars();
}