Consider two semantically equivalent pieces of code:
let x = Mutex::new(0);
if *x.lock().unwrap() == 0 {
*x.lock().unwrap() = 1;
}
let x = Mutex::new(0);
if let 0 = *x.lock().unwrap() {
*x.lock().unwrap() = 1;
}
The first one runs as expected, while the second one deadlocks. Why is guard destructor being run by if
but not by if let
? Where can I find documentation on this behavior?
The answer can be found on docs.rust-lang.org
. Specifically refer to if let
article, where it's said that:
An
if let
expression is equivalent to amatch
expression as follows:
if let PATS = EXPR { /* body */ } else { /*else */ }
is equivalent to
match EXPR { PATS => { /* body */ }, _ => { /* else */ } }
After heading to the match
article, it's said that
A match behaves differently depending on whether or not the scrutinee expression is a place expression or value expression.
If the scrutinee expression is a value expression, it is first evaluated into a temporary location, and the resulting value is sequentially compared to the patterns in the arms until a match is found. The first arm with a matching pattern is chosen as the branch target of the match, any variables bound by the pattern are assigned to local variables in the arm's block, and control enters the block.
... more about place expressions
In your case the scrutinee *x.lock().unwrap()
is a value expression, thus the guard's lifetime is the same as the lifetime of your main branch. Thus you get a deadlock, trying to .lock()
mutex again after it's already locked by your own if let
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With