为什么我不能从互斥锁中可变地借用单独的字段?

kmd*_*eko 4 rust

尝试通过以下方式获取对单独字段的可变引用MutexGuard

struct MyObject {
    pub a: i32,
    pub b: i32,
}

fn func_1(mtx: &Mutex<MyObject>) {
    let mut obj = mtx.lock().unwrap();
    let a = &mut obj.a;
    let b = &mut obj.b;

    *a += 1;
    *b *= 2;
}
Run Code Online (Sandbox Code Playgroud)

结果出现错误:

error[E0499]: cannot borrow `obj` as mutable more than once at a time
  --> src/main.rs:11:18
   |
10 |     let a = &mut obj.a;
   |                  --- first mutable borrow occurs here
11 |     let b = &mut obj.b;
   |                  ^^^ second mutable borrow occurs here
12 |     
13 |     *a += 1;
   |     ------- first borrow later used here
Run Code Online (Sandbox Code Playgroud)

这让我有点困惑。obj当是一个简单的可变引用 ( &mut MyObject)时,这有效。我认为也许该Deref特征是导致问题的原因,但如果obj&mut Box<MyObject>.

在Rust Playground上看到它。

我缺少什么?

wel*_*urm 6

Mutex::lock 返回一个 RAII 锁防护以及处理其所包含值的方法。要获得其包含的值&mut(以及随后的“分割借用”),您需要:

  • 将防护(由 返回lock)保存在单独的值中,因为只要访问该值,锁就需要存在。
  • &mut从守卫中提取值 as MutexGuard::deref_mut

这是更新的func_1

use std::ops::DerefMut;

fn func_1(mtx: &Mutex<MyObject>) {
    let mut guard = mtx.lock().unwrap();
    let obj = guard.deref_mut();
    let a = &mut obj.a;
    let b = &mut obj.b;

    *a += 1;
    *b *= 2;
}
Run Code Online (Sandbox Code Playgroud)