use*_*342 6 rust borrow-checker
为什么下面的代码不能编译(playground):
use std::collections::HashMap;
fn main() {
let mut h: HashMap<u32, u32> = HashMap::new();
h.insert(0, 0);
h.insert(1, h.remove(&0).unwrap());
}
Run Code Online (Sandbox Code Playgroud)
借阅检查员抱怨说:
error[E0499]: cannot borrow `h` as mutable more than once at a time
--> src/main.rs:6:17
|
6 | h.insert(1, h.remove(&0).unwrap());
| - ------ ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)
然而,代码是安全的,最后一行的几乎机械转换使它编译(playground):
//h.insert(1, h.remove(&0).unwrap());
let x = h.remove(&0).unwrap();
h.insert(1, x);
Run Code Online (Sandbox Code Playgroud)
我的理解是,这种问题可以通过非词法生命周期解决。这个问题是一个例子,还有很多其他问题。
毕竟,是否有一些微妙之处使第一个变体不正确,所以 Rust 拒绝它是正确的?还是 NLL 功能在所有情况下仍未完成?
您的问题也适用于可能更令人惊讶的相关案例 -&self在方法参数 requires 时调用方法&mut self:
use std::collections::HashMap;
fn main() {
let mut h: HashMap<u32, u32> = HashMap::new();
h.insert(0, 0);
h.contains_key(&h.remove(&0).unwrap());
}
Run Code Online (Sandbox Code Playgroud)
Rust 借用检查器使用它所谓的两阶段借用。我与 Niko Matsakis的聊天记录经过编辑:
两阶段借用的想法是,在实际使用之前,或多或少地将外部
&mut视为&借用。这使得它与内部兼容,因为两个混合,但它与内部不兼容。&&&mut如果我们想支持,我们就不得不增加一个新的借的-即“未激活”
&mut不会这样做的&,它会像其他的东西(&const也许......“别人可以变异")不太清楚这是否可以,而且它似乎添加了更多概念,因此我们选择不支持它。
正如您所说,这是安全的,因为内部借用在外部借用开始之前完成,但实际上在编译器中认识到此时过于复杂。
也可以看看: