不能作为不可变借用,因为它在函数参数中也作为可变借用 [英] Cannot borrow as immutable because it is also borrowed as mutable in function arguments

查看:27
本文介绍了不能作为不可变借用,因为它在函数参数中也作为可变借用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里发生了什么 (playground)?

struct Number {编号:i32}实现数{fn set(&mut self, new_num: i32) {self.num = new_num;}fn get(&self) ->i32 {self.num}}fn 主(){让 mut n = Number{ num: 0 };n.set(n.get() + 1);}

出现此错误:

error[E0502]: 不能借用 `n` 作为不可变的,因为它也被借用为可变的--><匿名>:17:11|17 |n.set(n.get() + 1);|- ^ - 可变借用到此结束|||||不可变借用发生在这里|可变借用发生在这里

但是,如果您只是将代码更改为此,它就可以工作:

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

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

解决方案

这一行:

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

脱糖为

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

错误信息现在可能更清楚了:

error[E0502]: 不能借用 `n` 作为不可变的,因为它也被借用为可变的--><匿名>:18:25|18 |Number::set(&mut n, n.get() + 1);|- ^ - 可变借用到此结束|||||不可变借用发生在这里|可变借用发生在这里

当 Rust 从左到右计算参数时,该代码等效于:

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

<块引用>

编者注:此代码示例直观地了解了潜在问题,但并不完全准确.即使使用非词法生命周期,扩展 代码仍然失败,但 原始 代码可以编译.有关问题的完整描述,请查看 借用检查器原始实现中的注释

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

这最初创建为 bug #6268,现在已集成进入RFC 2094非词法生命周期.如果您使用 Rust 1.36 或更新版本,NLL 会自动启用并且 您的代码现在可以编译而不会出错.

另见:

What is going on here (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);
}

Gives this error:

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

However if you simply change the code to this it works:

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

To me those look exactly equivalent - I mean, I would expect the former to be transformed to the latter during compilation. Doesn't Rust evaluate all function parameters before evaluating the next-level-up function call?

解决方案

This line:

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

is desugared into

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

The error message might be a bit more clear now:

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

As Rust evaluates arguments left to right, that code is equivalent to this:

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

Editor's note: This code example gives an intuitive sense of the underlying problem, but isn't completely accurate. The expanded code still fails even with non-lexical lifetimes, but the original code compiles. For the full description of the problem, review the comments in the original implementation of the borrow checker

It should now be obvious what is wrong. Swapping those first two lines fixes this, but Rust does not do that kind of control-flow analysis.

This was first created as bug #6268, now it is integrated into RFC 2094, non-lexical-lifetimes. If you use Rust 1.36 or newer, NLL is enabled automatically and your code will now compile without an error.

See also:

这篇关于不能作为不可变借用,因为它在函数参数中也作为可变借用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆