I am having trouble understanding how to modify Option inside a Mutex.
When there's no Option, it works fine
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());
However, when I wrap the value in Some
, I had to manually use ref mut
and such (I found it from here) because the lock().unwrap()
returns MutexGuard
, not the Option
itself.
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());
Any idea which Rust concept causes this? And also are there any more data types besides Option
which returns MutexGuard
and not its original value?
Actually, Mutex::lock
returns Result<MutexGuard, ..>
in both cases. Though, this type has interesting trait implementation: Deref
and DerefMut
. These allow explicit dereference via *
operator. Consider this example with the explicit types:
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;
And, of course, you can use Option
similarly:
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 => {},
}
Notice, the last match example is exactly the same as yours but uses a slightly different syntax. Playground.