为什么 Rust borrow checker 会忽略函数参数中的可变指针?

Why does Rust borrow checker ignores the mutable pointer among the function parameters?

我刚刚被关于生命周期的 rust 编译错误弄糊涂了。

假设代码片段如下所示:

fn process(map: &mut HashMap<String, String>, key: String) {
    match map.get_mut(&key) {
        Some(value) => println!("value: {}", value),
        None => {
            map.insert(key, String::new());
        }
    }
}

我这样称呼它:

fn main() {
    let mut map = HashMap::<String, String>::new();
    let key = String::from("name");
    process(&mut map, key);
}

据我所知(忽略 NLL 特性),map.get_mut returns 一个 Option<&mut String> 类型,其中 &mut String 是一个指向部分地图的借用指针,指针贯穿整个 match 块。然后在 None 分支内,map.insert(key, String::new()) 自动创建另一个 &mut HashMap<String, String> 指针,它也指向地图。两个指针两次借用同一个map作为mutable,所以导致:

error[E0499]: cannot borrow `*map` as mutable more than once at a time
 --> test.rs:7:13
  |
4 |     match map.get_mut(&key) {
  |           --- first mutable borrow occurs here
...
7 |             map.insert(key, String::new());
  |             ^^^ second mutable borrow occurs here
8 |         }
9 |     }
  |     - first borrow ends here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.

但我的问题是:

函数fn process的第一个参数是一个可变指针本身(&mut HashMap<String, String>),它也指向地图。根据上面的规则,当下一行调用 map.get_mut(&key) 时,会发生第二个可变借用。为什么编译器不会抛出这样的错误(内存安全的风险?):

fn process(map: &mut HashMap<String, String>, key: String)
           --- first mutable borrow occurs here
    match map.get_mut(&key)
    ^^^ second mutable borrow occurs here // the return value of type Option<&mut String>

我是 Rust 的新手,如有任何提示,我们将不胜感激。

为了执行对 get_mut 的调用,Rust 执行隐式 reborrow.

A reborrow 相当于从可变引用中借用,然后将引用展平。也就是说,给定类型 &'a T 的可变引用,从中借用会产生 &'b &'a T(注意有两个不同的生命周期;'b'a 短),并且展平参考产量 &'b T.

Rust 知道生命周期 'b 的借用是从生命周期 'a 的借用派生出来的。因此,只要 borrow 'b 还活着,borrow 'a 就会被冻结。

在 NLL 之前,为调用 get_mut 获得的借用将在整个 match 块中存在,因为 get_mut returns 一个使借用保持活动的值。 map.insert(...) 也尝试从 map 重新借用,但是由于从 map 的第一次重新借用仍然有效,所以这是一个错误。