Rust 使用现有可变引用的嵌套方法调用
以下代码已成功编译:Rust 使用现有可变引用的嵌套方法调用,rust,reference,borrow-checker,borrowing,Rust,Reference,Borrow Checker,Borrowing,以下代码已成功编译: 让mut v=vec![1]; 设r=&mut v; r、 推(r.len()); 虽然这一次失败了: 让mut v=vec![1]; 设r=&mut v; r、 推(v.len()); 有误: error[E0502]:无法将'v'作为不可变项借用,因为它也是作为可变项借用的 | |设r=&mut v; |----可变借用发生在这里 |右推(v.len()); |^此处发生不可变借用 |r.push(r.len()); |-可变借用稍后在此处使用 为什么第一个示例
让mut v=vec![1];
设r=&mut v;
r、 推(r.len());
虽然这一次失败了:
让mut v=vec![1];
设r=&mut v;
r、 推(v.len());
有误:
error[E0502]:无法将'v'作为不可变项借用,因为它也是作为可变项借用的
|
|设r=&mut v;
|----可变借用发生在这里
|右推(v.len());
|^此处发生不可变借用
|r.push(r.len());
|-可变借用稍后在此处使用
- 为什么第一个示例编译正确?是因为在外部调用和内部调用中使用了相同的引用:
?还是因为它应用了?还是别的什么r
- 既然第一个例子成功了,为什么第二个例子失败了?为什么这个规则不适用于这里
r
,因此没有多个借用。
但是,如果是这样,为什么下面的代码无法编译
让mut v=vec![1];
设r=&mut v;
r、 push({r.push(0);1});
在第二个示例中,当您尝试获取其长度时,v
仍然是可变借用的Vec::len
接受&self
,因此获取其长度意味着不可变地借用,而它已经可变地借用
通过r
访问len()
请注意,即使第一个示例在Rust 1.30及更早版本(或2015版的1.35)中也失败了,因为它依赖于NLL(非词汇生存期)。NLL的问题是,知道什么是允许的并不是完全直观的。从本质上说,这意味着不超过数据词汇范围的借词是可以的,还有一些其他直观上正确的情况。您的第三个示例是NLL仍不允许的案例之一。第一个示例:
让mut v=vec![1];
设r=&mut v;
r、 推(r.len());
如果没有2阶段借用,代码将无法编译,因为外部调用将创建一个r
:&mut*r
,而内部调用将创建一个相同值的新的不可变重新加载:&*r
对于两阶段借用,第一次重新箭头转换为&mut2*r
,然后在第二次重新箭头超出范围时激活
第二个示例:
让mut v=vec![1];
设r=&mut v;
r、 推(v.len());
即使使用2阶段借用,它也不会编译
内部调用导致重新出现与r
冲突的v
:&mut v
第三个示例:
让mut v=vec![1];
设r=&mut v;
r、 push({r.push(0);0});
即使使用2阶段借用,它也不会编译
内部调用需要&mut2
重传*r
,这是2阶段借用不允许的,因为外部调用已经创建了&mut2
重传*r
参考资料:
我在这里发布了同样的问题:我想知道为什么NLL不允许使用第三个示例。编译器如何评估代码来考虑第一个例子OK,而第三个则不行?这确实是我的观点。词法寿命是可以推理的,但NLL只是意味着“允许更多”,精确描述限制并不容易。使用NLL实现借用检查器(无论是两阶段模型、堆叠借用还是粉笔)是很难考虑的,因为它是根据MIR,而不是您实际编写的代码。也许可以想出一个好的心智模型来预测什么样的锈迹代码会或不会满足当前的借用检查器实现,但我没有。总的来说,基于经验,我对词汇借用和一些非词汇案例的理解有信心。我不能写下规则,除了词汇上的例子,我也不相信有很多人可以。我甚至不相信这项努力是值得的:我还希望将来会有更多的项目被接受,无论是从改进到当前的实现,还是从最终改为粉笔。