使用现有可变引用的嵌套方法调用
Nested method calls with existing mutable references
以下代码编译成功:
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
?还是因为它应用了RFC 2025, Two-Phase Borrows?还是别的?
- 第一个例子成功了,为什么第二个例子失败了?为什么 RFC 2025, Two-Phase Borrows 在这里不适用?
我怀疑在第一个示例中没有错误,因为编译器不创建中间引用并且它使用相同的引用:r
因此没有多次借用。
但是,如果是这样,为什么下面的代码编译失败
let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);1});
在第二个示例中,当您尝试获取其长度时,v
仍然是可变借用的。 Vec::len
需要 &self
,因此获取它的长度意味着在它已经可变地借用时不变地借用。
通过r
访问len()
还是可以的,因为你是在通过借同样的借,而不是再次借。
请注意,即使第一个示例在 Rust 1.30 及更早版本(或 2015 版的 1.35)中也会失败,因为它依赖于 NLL(非词法生命周期)。 NLL 的问题在于,了解允许的内容并不完全直观。从本质上讲,这意味着不超过数据词法范围的借用是可以的,并且 还有其他几个 直观正确的情况。你的第三个例子是 NLL 仍然不允许的情况之一。
第一个例子:
let mut v = vec![1];
let r = &mut v;
r.push(r.len());
如果没有 2-phase 借用,代码将无法编译,因为外部调用创建了 r
的重新借用:&mut *r
,并且内部调用创建了一个新的相同值的不可变重新借用:&*r
.
对于双阶段借用,第一次借用转换为 &mut2 *r
并在第二次借用超出范围时激活。
第二个例子:
let mut v = vec![1];
let r = &mut v;
r.push(v.len());
即使使用 2-phase 借用它也不会编译。
内部调用导致 v
的重借:&mut v
与 r
冲突。
第三个例子:
let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);0});
即使使用 2-phase 借用它也不会编译。
内部调用需要 &mut2
次 *r
的再借用,这是 2 阶段借用所不允许的,因为外部调用已经创建了 &mut2
次 [=21= 的再借用].
参考文献:
以下代码编译成功:
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
?还是因为它应用了RFC 2025, Two-Phase Borrows?还是别的? - 第一个例子成功了,为什么第二个例子失败了?为什么 RFC 2025, Two-Phase Borrows 在这里不适用?
我怀疑在第一个示例中没有错误,因为编译器不创建中间引用并且它使用相同的引用:r
因此没有多次借用。
但是,如果是这样,为什么下面的代码编译失败
let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);1});
在第二个示例中,当您尝试获取其长度时,v
仍然是可变借用的。 Vec::len
需要 &self
,因此获取它的长度意味着在它已经可变地借用时不变地借用。
通过r
访问len()
还是可以的,因为你是在通过借同样的借,而不是再次借。
请注意,即使第一个示例在 Rust 1.30 及更早版本(或 2015 版的 1.35)中也会失败,因为它依赖于 NLL(非词法生命周期)。 NLL 的问题在于,了解允许的内容并不完全直观。从本质上讲,这意味着不超过数据词法范围的借用是可以的,并且 还有其他几个 直观正确的情况。你的第三个例子是 NLL 仍然不允许的情况之一。
第一个例子:
let mut v = vec![1];
let r = &mut v;
r.push(r.len());
如果没有 2-phase 借用,代码将无法编译,因为外部调用创建了 r
的重新借用:&mut *r
,并且内部调用创建了一个新的相同值的不可变重新借用:&*r
.
对于双阶段借用,第一次借用转换为 &mut2 *r
并在第二次借用超出范围时激活。
第二个例子:
let mut v = vec![1];
let r = &mut v;
r.push(v.len());
即使使用 2-phase 借用它也不会编译。
内部调用导致 v
的重借:&mut v
与 r
冲突。
第三个例子:
let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);0});
即使使用 2-phase 借用它也不会编译。
内部调用需要 &mut2
次 *r
的再借用,这是 2 阶段借用所不允许的,因为外部调用已经创建了 &mut2
次 [=21= 的再借用].
参考文献: