Mutex 中的可变借用失败

Mutable borrow fail in Mutex

我收到有关 Mutex 中可变借用失败的错误。

这是代码。 现在好了。但是,如果取消注释这两行,它将无法编译,这会将 state 包装到互斥锁中并将其展开。

为什么 Mutex 会有所不同?

use std::collections::HashMap;
use std::sync::Mutex;

struct State {
    h1: HashMap<String, String>,
    h2: HashMap<String, String>,
}

fn main() {
    let mut state = State {
        h1: HashMap::new(),
        h2: HashMap::new(),
    };

    // It fails to compile if uncommenting these 2 lines!
    //let state = Mutex::new(state);
    //let mut state = state.lock().unwrap();

    let v1 = state.h1.get_mut("abc").unwrap();
    let v2 = state.h2.get_mut("abc").unwrap();
    v1.push_str("123");
    v2.push_str("123");
}

如果取消注释 2 行的错误:

error[E0499]: cannot borrow `state` as mutable more than once at a time
  --> tmp.rs:20:14
   |
19 |     let v1 = state.h1.get_mut("abc").unwrap();
   |              ----- first mutable borrow occurs here
20 |     let v2 = state.h2.get_mut("abc").unwrap();
   |              ^^^^^ second mutable borrow occurs here
21 |     v1.push_str("123");
   |     -- first borrow later used here

===编辑===

如果更改一些代码顺序就可以了:

    let state = Mutex::new(state);
    let mut state = state.lock().unwrap();

    let v1 = state.h1.get_mut("abc").unwrap();
    v1.push_str("123");
    let v2 = state.h2.get_mut("abc").unwrap();
    v2.push_str("123");

似乎 v1 持有 state 的引用。如果v1结束,则丢弃引用,然后state可以再次借用。

为什么 v1 持有 state 的引用?

====编辑====

@Alexey Larionov 给出了答案。我发现了一个类似的question。我应该通过 deref_mut() 手动从 MutexGuard 中获取 state。所以添加这一行就可以了:

    let state = state.deref_mut();

通过这样做,您可以获取 2 个对状态本身的可变引用。要解决它,您可以重新调整 get_mut 调用之一:

fn main() {
    let mut state = State {
        h1: HashMap::new(),
        h2: HashMap::new(),
    };

    // It fails to compile if uncommenting these 2 lines!
    let state = Mutex::new(state);
    let mut state = state.lock().unwrap();

    {
        let v1 = state.h1.get_mut("abc").unwrap();
        v1.push_str("123");
    }

    let v2 = state.h2.get_mut("abc").unwrap();
    v2.push_str("123");
}

这样,当您获得第二个参考时,第一个参考已经被丢弃。

Playground

只是为了详细说明@Netwave 的回答,以防万一没有 Mutex 你不会得到这样的错误,因为这样做

let mut state = State {
        h1: HashMap::new(),
        h2: HashMap::new(),
};
let v1 = state.h1.get_mut("abc").unwrap();
let v2 = state.h2.get_mut("abc").unwrap();

v1可变借用state.h1v2可变借用state.h2,两者都算作state的不可变借用,以防止将 state 移出(例如 let state2 = state; 而存在其他借用)。由于所有借用规则都已满足(或者 每个对象最多有一个可变借用 每个对象最多有多个不可变借用),允许借用。

Mutex的情况下这一行

let mut state = state.lock().unwrap();

生成类型 MutexGuard::<State>state。通过这种方式使用它

let v1 = state.h1.get_mut("abc").unwrap();

Rust 不会在 MutexGuard::<State> 中找到 h1,这就是为什么它将使用 DerefMut 特征从中隐式地获取 &mut State。那就是你可变地借用 state 的地方。由于您稍后对 v2 使用了类似的构造,因此您将尝试在 state 上获得第二个可变借用,从而收到错误