Hey guys,
I'm pretty new to rust but I'm having decent experience in developing developing.
Here is some small code snippet, that really boggles my mind:
use std::sync::{Mutex, Arc};
struct Test { value: i32 }
impl Test {
fn value(&self) -> i32 { self.value }
fn value_mut(&mut self) -> &mut i32 { &mut self.value }
}
fn do_something(value: Arc<Mutex<Test>>) {
match { value.lock().unwrap().value() } {
2 => {
println!("Value is 2");
*value.lock().unwrap().value_mut() = 3 as i32;
println!("Value is now 3");
},
_ => println!("Value not 2")
}
}
fn main() {
let value = Arc::new(Mutex::new(Test{ value: 2 }));
do_something(value);
}
My expectations would be, that this runs fine without any deadlock, but it dosn't.
The cause of this behaviour is, that match { value.lock().unwrap().value() } ... seems to capture the MutexGuard for the whole match body, which seems pretty odd for me, especially since { value.lock().unwrap().value() } is an independent block, returning i32.
My question is:
Is this a bug or intended behaviour? If so why (it's pretty contra intuitive for me)?
PS: This also applies for if let expressions
PPS: I tried to google a bit, but I cant really phrase my question into keywords, which lead to no satisfactory result.
The scrutinee of a match expression is not a temporary scope, so temporaries in the scrutinee can be dropped after the match expression. For example, the temporary for 1 in match 1 { ref mut z => z }; lives until the end of the statement.
To google some more you can search for phrases like "scrutinee" and "drop order".
Well... I think I now start understanding the thing.
My assumption was that { value.lock().unwrap().value() } is actually a block which causes the temporary MutexGuard to be drooped when evaluating it.
After some thoughts I came up with the following syntax which looks way more complicated that it should be. Is there may a better approch?
match { let x = value.lock().unwrap().value(); x } {
2 => {
println!("Value is 2");
*value.lock().unwrap().value_mut() = 3 as i32;
println!("Value is now 3");
},
_ => println!("Value not 2")
}
fn do_something(value: Arc<Mutex<Test>>) {
let value = value.lock().unwrap();
match value.value() {
2 => {
println!("Value is 2");
*value.value_mut() = 3 as i32;
println!("Value is now 3");
},
_ => println!("Value not 2")
}
}