rust - 为什么可变的 self 借用不会变成不可变的?

标签 rust borrow-checker

此代码未能通过可怕的借用检查器 (playground):

struct Data {
    a: i32,
    b: i32,
    c: i32,
}

impl Data {
    fn reference_to_a(&mut self) -> &i32 {
        self.c = 1;
        &self.a
    }
    fn get_b(&self) -> i32 {
        self.b
    }
}

fn main() {
    let mut dat = Data{ a: 1, b: 2, c: 3 };
    let aref = dat.reference_to_a();
    println!("{}", dat.get_b());
}

由于实现了非词法生命周期,因此需要触发错误:

fn main() {
    let mut dat = Data { a: 1, b: 2, c: 3 };
    let aref = dat.reference_to_a();
    let b = dat.get_b();
    println!("{:?}, {}", aref, b);
}

错误:

error[E0502]: cannot borrow `dat` as immutable because it is also borrowed as mutable
  --> <anon>:19:20
   |
18 |     let aref = dat.reference_to_a();
   |                --- mutable borrow occurs here
19 |     println!("{}", dat.get_b());
   |                    ^^^ immutable borrow occurs here
20 | }
   | - mutable borrow ends here

这是为什么?我本以为 dat 的可变借用在 reference_to_a() 返回时被转换为不可变借用,因为该函数只返回一个不可变引用。借用检查器还不够聪明吗?这是有计划的吗?有解决办法吗?

最佳答案

生命周期与引用是否可变无关。通过代码工作:

fn reference_to_a(&mut self) -> &i32

虽然省略了生命周期,但这等同于:

fn reference_to_a<'a>(&'a mut self) -> &'a i32

即输入和输出生命周期相同。这是为这样的函数分配生命周期的唯一方法(除非它返回对全局数据的 &'static 引用),因为您不能从无到有地弥补输出生命周期。

这意味着,如果您通过将返回值保存在变量中来保持其事件状态,您也将保持 &mut self 事件状态。

另一种思考方式是 &i32&mut self 的子借用,因此仅在到期之前有效。

正如@aSpex 指出的那样,这是 covered in the nomicon .

关于rust - 为什么可变的 self 借用不会变成不可变的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51831126/

相关文章:

rust - 大(负)数的模乘反函数

rust - 有没有办法将类型名称放入 Rust 宏中?

rust - 如何在不阻塞父任务的情况下在另一个任务中生成长时间运行的 Tokio 任务?

rust - 借用编译SQL语句的问题

reference - 如何创建一个工厂函数,其中您正在创建的数据需要引用?

rust - 为什么分配时会得到 "temporary value dropped while borrowed",但通过函数传递时却不会?

rust - 从函数返回的临时引用

rust - 我怎样才能在原始 crate 中使用另一个 crate 中的特征实现?

rust - 谁借用了一个变量?

rust - 如何使用滑动窗口对生成迭代器?