【问题标题】:Rust accessing Option from mutexRust 从互斥锁访问选项
【发布时间】:2020-06-07 16:17:55
【问题描述】:

我无法理解如何在 Mutex 中修改 Option。

当没有选项时,它可以正常工作

let mut my_int = Arc::new(Mutex::new(5));

let my_int_clone = Arc::clone(&my_int);

thread::spawn(move || {
  let mut my_int = my_int_clone.lock().unwrap();
  *my_int += 1;
}).join();

let my_int_clone_print = Arc::clone(&my_int);
println!("Value: {}", my_int_clone_print.lock().unwrap());

但是,当我将值包装在Some 中时,我不得不手动使用ref mut 等(我从here 找到它)因为lock().unwrap() 返回MutexGuard,而不是Option 本身.

let mut my_int = Arc::new(Mutex::new(Some(5)));

let my_int_clone = Arc::clone(&my_int);

thread::spawn(move || {
  let mut my_int = my_int_clone.lock().unwrap();

  match *my_int {
    Some(ref mut val) => {
      *val += 1;
    },
    None => {
      println!("Value is None. Doing nothing..");
    }
  }

}).join();

let my_int_clone_print = Arc::clone(&my_int);
println!("Value: {}", my_int_clone_print.lock().unwrap());

知道是哪个 Rust 概念导致了这种情况吗?除了返回MutexGuard而不是其原始值的Option之外,还有其他数据类型吗?

【问题讨论】:

  • 请注意,在 StackOverflow 上,当问题解决后,提问的人应该accept 最值得回答。这会从未回答的问题列表中删除该问题,为未来的访问者提供关于哪个答案是最佳答案的提示(在原始发布者的眼中),并以象征性声誉奖奖励撰写该答案的志愿者。如果答案不能解决您的问题,您可能需要编辑问题以澄清它。

标签: concurrency rust mutex


【解决方案1】:

实际上,Mutex::lock returns Result<MutexGuard, ..> 在这两种情况下都是如此。不过,这种类型有有趣的 trait 实现:DerefDerefMut。这些允许通过* 运算符显式取消引用。考虑这个带有显式类型的例子:

let mutex = Mutex::new(1i32);
let mut guard: MutexGuard<'_, i32> = mutex.lock().unwrap();

// This dereferences to &mut i32 
// because assignment operator works with &mut self.
*guard = 2;

// Nevertheless, for an explicit borrowing you need &mut
// because otherwise it would be moved from the guard.
let inner: &mut i32 = &mut *guard;

当然,您也可以类似地使用Option

let mutex = Mutex::new(Some(1i32));
let mut guard: MutexGuard<'_, Option<i32>> = mutex.lock().unwrap();

// Directly change inner value
*guard = Some(2);

// or use in match, notice &mut borrowing
match &mut *guard {
    Some(x) => *x += 1,
    None => {},
}

请注意,最后一个匹配示例与您的完全相同,但使用的语法略有不同。 Playground.

【讨论】:

    【解决方案2】:

    除了返回MutexGuard而不是其原始值的Option之外,还有其他数据类型吗?

    MutexGuard 无法返回原始值,因为移动该值会使互斥锁无效。相反,它是一个为原始值提供可变引用的包装器。

    这绝不是 Option 特有的,MutexGuardMutex::lock 始终返回的内容。例如这段代码:

    let m = Mutex::<bool>::new(false);
    let () = m.lock().unwrap();
    

    ...会抱怨m.lock().unwrap()返回的类型是std::sync::MutexGuard&lt;'_, bool&gt;

    MutexGuard 在引用不超过守卫的情况下授予对数据的访问权限。 *my_int += 1 有效,因为MutexGuard 实现了DerefMut,它告诉* 操作员要处理的引用。 * 运算符与 Option 完美配合;例如:

    let m = Mutex::<Option<i32>>::new(Some(0));
    let mut my_int = m.lock().unwrap();
    *my_int = Some(100);
    

    匹配*my_int 可以在没有ref mut 的情况下完成,但随后*my_int 将复制选项(只要其内容为Copy 即可)并且修改值不会对选项本身产生影响.这又不是MutexGuard 特有的,这就是匹配的工作方式。需要ref mut 才能让您对选项内的数据进行可变访问。

    【讨论】:

      猜你喜欢
      • 2018-05-23
      • 1970-01-01
      • 2011-01-12
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 2010-12-17
      • 1970-01-01
      相关资源
      最近更新 更多