具有现有可变引用的嵌套方法调用

问题描述

以下代码编译成功:

let mut v = vec![1];
let r = &mut v;
r.push(r.len());

虽然这个失败了:

let mut v = vec![1];
let r = &mut v;
r.push(v.len());

错误

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
    |
    |     let r = &mut v;
    |             ------ mutable borrow occurs here
    |     r.push(v.len());
    |            ^ immutable borrow occurs here
    |     r.push(r.len());
    |     - mutable borrow later used here

我怀疑在第一个示例中没有错误,因为编译器没有创建中间引用并且它使用相同的引用:r 以便没有多次借用。 但是,如果是这样,为什么下面的代码无法编译

let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);1});

解决方法

在第二个示例中,当您尝试获取其长度时,仍会可变地借用 vVec::len 需要 &self,因此获得它的长度意味着在它已经被可变地借用时不变地借用。

通过 len() 访问 r 仍然可以,因为您正在借用 同一个借用,而不是再次借用。


请注意,即使第一个示例在 Rust 1.30 及更早版本(或 2015 版的 1.35)中也失败了,因为它依赖于 NLL(非词法生命周期)。 NLL 的问题在于,了解允许的内容并不完全直观。从本质上讲,这意味着借用不会超过数据的词汇范围,并且还有其他几个直观正确的情况。你的第三个例子是 NLL 仍然不允许的情况之一。

,

第一个示例:

let mut v = vec![1];
let r = &mut v;
r.push(r.len());

如果没有两阶段借用,代码将无法编译,因为外部调用创建了 r 的重新借用:&mut *r,而内部调用创建了一个新的相同值的不可变重新借用:{{1 }}。

对于两阶段借用,第一个再借用转换为 &*r,然后在第二个再借用超出范围时激活。

第二个例子:

&mut2 *r

即使使用两阶段借用,它也不会编译。

内部调用导致重新借用 let mut v = vec![1]; let r = &mut v; r.push(v.len()); : v&mut v 冲突。

第三个例子:

r

即使使用 2-phase 借用,它也不会编译。

内部调用需要 let mut v = vec![1]; let r = &mut v; r.push({r.push(0);0}); &mut2 重新借用,这是两阶段借用所不允许的,因为外部调用已经创建了 *r&mut2 重新借用。

参考资料