为什么HashMap :: get_mut()取得了该范围其余部分的地图所有权?

Ian*_*ews 8 rust

我有以下代码将一些值插入HashMap,然后将它们取回:

use std::collections::HashMap;

fn things() {
    let mut map = HashMap::new();
    map.insert(5, "thing");
    map.insert(4, "world");
    map.insert(1, "hello");
    let mut thing = map.remove(&5);
    let mut world = map.get_mut(&4);
    let mut hello = map.get_mut(&1);
}
Run Code Online (Sandbox Code Playgroud)

尝试编译此代码会出现以下错误:

error[E0499]: cannot borrow `map` as mutable more than once at a time
  --> src/main.rs:10:21
   |
9  |     let mut world = map.get_mut(&4);
   |                     --- first mutable borrow occurs here
10 |     let mut hello = map.get_mut(&1);
   |                     ^^^ second mutable borrow occurs here
11 | }
   | - first borrow ends here
Run Code Online (Sandbox Code Playgroud)

在仔细阅读remove()get_mut()方法的API文档之后(幸运的是它们彼此非常接近!)从方法签名中remove()没有任何东西可以突显出为什么方法不会在当前范围的其余部分可变地借用地图该get_mut()方法做.

我拥有的另一条数据也让我感到困惑的是这段代码编译:

use std::collections::HashMap;

fn things() {
    let mut map = HashMap::new();
    map.insert(5, "thing");
    map.insert(4, "world");
    map.insert(1, "hello");
    let mut thing = map.remove(&5);
    map.get_mut(&4);
    let mut hello = map.get_mut(&1);
}
Run Code Online (Sandbox Code Playgroud)

不存储第一次调用的结果get_mut()不会导致映射被其他范围的可变借用?我怎么能从文档中了解到这一点?我错过了别的什么吗?

She*_*ter 11

此错误是在非词汇生命周期之前实施借用检查器的限制.启用后,原始代码将按原样运行:

use std::collections::HashMap;

fn things() {
    let mut map = HashMap::new();
    map.insert(5, "thing");
    map.insert(4, "world");
    map.insert(1, "hello");
    let mut thing = map.remove(&5);
    let mut world = map.get_mut(&4);
    let mut hello = map.get_mut(&1);
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

这是因为编译器更智能,并且world在您到达时可以看到您不再使用map.get_mut(&1)它,因此它不再需要具有有效的引用.

通过添加显式范围,您可以在以前版本的Rust中获得等效代码:

let mut thing = map.remove(&5);
{
    let mut world = map.get_mut(&4);
}
let mut hello = map.get_mut(&1);
Run Code Online (Sandbox Code Playgroud)

为什么HashMap::get_mut()取得地图的所有权

它绝对不会那样做.所有权是Rust代码中的精确术语.请注意,错误消息具体说明

以前的借款map发生在这里

一个是不是所有权.如果我借你的车,我没有你的车.

你真正的问题是"为什么它会在剩下的范围内借用它".我们来看看签名:

fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> 
where
    K: Borrow<Q>,
    Q: Hash + Eq,
Run Code Online (Sandbox Code Playgroud)

用语言来说,这可以理解为

给定a HashMap(&mut self)的可变引用以及可用于查找key(K: Borrow<Q>, Q: Hash + Eq)的内容,如果匹配(Option<&mut V>),则返回对该值的可变引用

然而,返回可变引用将被改变的东西HashMap,这就是为什么它是一个可变引用的.您只能拥有多个不可变借款或一次可变借款.这可以防止编写导致不一致和安全问题的代码.

我们来看看remove:

fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> 
where
    K: Borrow<Q>, 
    Q: Hash + Eq,
Run Code Online (Sandbox Code Playgroud)

这将返回一个拥有的值,而不是对该引用的引用HashMap.方法完成后,借用地图就结束了.

  • 我想我拥有它.当你有一个方法在struct上可变地借用`self`并且该方法返回一个可变引用时,唯一有效的假设是可变引用是指该结构上的某个字段,它可以传递地保持对struct的借用.谢谢你的澄清! (2认同)