Prevent 不能借用 `*self` 作为不可变的,因为在访问结构体中不相交的字段时它也被借用为可变的?

Roy*_*son 3 rust borrow-checker

先前的问题是,这不是以下内容的重复:

我有以下结构:

struct Foo {
    data: Vec<Bar>,
    a: usize,
}

struct Bar {
    b: usize
}
Run Code Online (Sandbox Code Playgroud)

在里面impl Foo,我有以下方法:

fn example(&mut self, c: usize) {
    let baz = &mut self.data[c];
    let z = self.calc(c);
    baz.b = 42 + z;
}

fn calc(&self, x: usize) -> usize {
    self.a * x
}
Run Code Online (Sandbox Code Playgroud)

当然,Rust 编译器会抛出一个错误,大致是“在创建 时发生可变借用baz,然后在调用时执行不可变借用self.calc,最后在分配给 时使用可变借用baz.a

但是,我正在访问结构上的不相交字段,因为calc从不读取通过 写入的数据baz

有没有办法通知 Rust 编译器这一点?

use*_*968 8

问题是作为接收者的 的Foo::calc签名&self。这保证calc不存在对所有 的可变引用self,包括其任何字段;也就是说,从主体的角度来看,所有 of 都Foo保证是不可变的。calc这对于代码来说是不可能的,因为在可变借用仍然处于活动状态时self.calc(c)需要一成不变地借用self全部) 。self

事实上,calc从不读取正在写入的数据baz是无关紧要的。在 Rust 中,关于函数或方法的所有信息都在签名中公开;编译器从不“查看”函数来确定它是否是特殊情况。

calc您可以通过不要求作为&self接收者来避免该问题。例如,通过在调用 ( Self::calc(&self.a, c)) 之前借用各个字段,或者如下例所示,根本不借用self

impl Foo {
    fn example(&mut self, c: usize) {
        let baz = &mut self.data[c];
        // This avoids borrowing `self` in its entirety...
        let z = Self::calc(self.a, c);
        baz.b = 42 + z;
    }

    fn calc(a: usize, x: usize) -> usize {
        a * x
    }
}
Run Code Online (Sandbox Code Playgroud)