Rust中match为何比if持有引用的时间更长?
Rust中match与if在锁持有生命周期上的差异解析
问题场景
首先定义一个简单结构体:
struct Foo; impl Foo { fn is_valid(&self) -> bool { true } }
再用Tokio的互斥锁包裹该结构体:
let foo = tokio::sync::Mutex::new(Foo);
用match导致死锁
match foo.lock().await.is_valid() { _ => foo.lock().await.is_valid(), // 死锁 };
这段代码无法执行完成,因为第二次尝试获取锁时,第一个锁仍未释放。
用if可正常执行
if foo.lock().await.is_valid() { foo.lock().await.is_valid(); // 正常执行 }
这段代码能正常完成,锁会被成功获取两次。
背后的原因
这确实是因为match持有临时值(此处为互斥锁的MutexGuard)的时间比if更长,核心源于Rust对临时值销毁时机的规则差异:
if表达式的临时值销毁时机:
if的条件表达式求值完成后,只要其结果没有被后续代码借用,临时值就会立即销毁。这里foo.lock().await返回的MutexGuard仅用来调用is_valid()得到布尔值,之后Guard不再被引用,因此会立刻被释放,锁也随之释放。match表达式的临时值销毁时机:
match后的 scrutinee(即匹配的目标表达式)会被整个match块持有,直到整个match执行完毕才会销毁。Rust这样设计是为了保证在所有匹配分支中,scrutinee的值始终有效(比如分支中若用到了scrutinee的引用,不会出现悬垂引用)。即便你这里只用到了is_valid()的返回值,Rust仍会保留整个scrutinee(包括MutexGuard)直到match结束,导致第一个锁持续被持有,第二次获取锁时就触发了死锁。
简单总结:if条件的临时值在判断完成后立即销毁,而match的目标表达式临时值会存活整个match块的生命周期。
内容的提问来源于stack exchange,提问作者itarato
相关产品推荐
相关产品推荐

