函数参数中的可变借用

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 功能在所有情况下仍未完成?

She*_*ter 5

您的问题也适用于可能更令人惊讶的相关案例 -&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也许......“别人可以变异")

不太清楚这是否可以,而且它似乎添加了更多概念,因此我们选择不支持它。

正如您所说,这是安全的,因为内部借用在外部借用开始之前完成,但实际上在编译器中认识到此时过于复杂。

也可以看看: