【问题标题】:Cannot borrow as immutable because it is also borrowed as mutable in function arguments不能作为不可变借用,因为它在函数参数中也作为可变借用
【发布时间】:2017-05-02 10:06:57
【问题描述】:

这里发生了什么 (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】:

这一行:

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);

编者注:此代码示例对潜在问题给出了直观的认识,但并不完全准确。 扩展的代码即使在非词法生命周期中仍然失败,但原始代码可以编译。有关问题的完整描述,请查看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

另见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    相关资源
    最近更新 更多