不能借为不可变的,因为它在函数参数中也被借为可变的

问题描述 投票:22回答:1

这里发生什么事[playground?]

struct Number {
    num: i32
}

impl Number {
    fn set(&mut self, new_num: i32) {
        self.num = new_num;
    }
    fn get(&self) -> i32 {
        self.num
    }
}

fn main() {
    let mut n = Number{ num: 0 };
    n.set(n.get() + 1);
}

给出此错误:

error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable
  --> <anon>:17:11
   |
17 |     n.set(n.get() + 1);
   |     -     ^          - mutable borrow ends here
   |     |     |
   |     |     immutable borrow occurs here
   |     mutable borrow occurs here

但是,如果您只是简单地将代码更改为此,则可以:

fn main() {
    let mut n = Number{ num: 0 };
    let tmp = n.get() + 1;
    n.set(tmp);
}

对我来说,这些看起来完全等效-我的意思是,我希望在编译过程中将前者转换为后者。 Rust在评估下一级函数调用之前不评估所有函数参数吗?

rust borrow-checker
1个回答
23
投票

此行:

n.set(n.get() + 1);

已减为

Number::set(&mut n, n.get() + 1);

错误消息现在可能会更加清晰:

error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable
  --> <anon>:18:25
   |
18 |     Number::set(&mut n, n.get() + 1);
   |                      -  ^          - mutable borrow ends here
   |                      |  |
   |                      |  immutable borrow occurs here
   |                      mutable borrow occurs here

Rust从左到右评估参数时,该代码与此等效:

let arg1 = &mut n;
let arg2 = n.get() + 1;
Number::set(arg1, arg2);

编者注:此代码示例直观地说明了潜在问题,但并不完全准确。即使使用非词法生存期,expanded代码仍然会失败,但是原始代码会编译。有关问题的完整说明,请查看the comments in the original implementation of the borrow checker

现在应该很明显出了什么问题。交换前两行可以解决此问题,但是Rust不会进行这种控制流分析。

此文件最初创建为bug #6268,现在已集成到RFC 2094non-lexical-lifetimes中。如果您使用Rust 1.36或更高版本,则会自动启用NLL并启用your code will now compile without an error

© www.soinside.com 2019 - 2024. All rights reserved.