为什么这个 MutexGuard 没有被丢弃?

Why is this MutexGuard not dropped?

Chapter 20 of The Rust Book中,构建了一个线程池的示例实现。作业通过单生产者多消费者通道传递给工人:每个工人都有一个 Arc<Mutex<Receiver>> 来从队列中挑选作业。

工作线程主体的第一个示例如下所示:

loop {
    let job = receiver.lock().unwrap().recv().unwrap();

    println!("Worker {} got a job; executing.", id);

    job();
}

当我看到这个时,我的第一个想法是 "but the mutex is held while job is run"(即我没想到互斥锁会被释放,直到 lock 的 return 值最后超出范围循环)。

然而这本书提供了第二个例子:

while let Ok(job) = receiver.lock().unwrap().recv() {
    println!("Worker {} got a job; executing.", id);

    job();
}

书上说这个例子展示了我描述的问题,即"the lock remains held for the duration of the call to job()"。它继续说前一个例子逃避了这个问题,因为 "the MutexGuard returned from the lock method is dropped as soon as the let job statement ends".

最后一部分听起来好像,因为 MutexGuard 从未实际分配给变量,它的生命周期在表达式完成计算后立即结束。那是有道理的。但是第二个例子不也是如此吗?为什么在 while 表达式中会改变 MutexGuard 值的生命周期?

临时变量在语句末尾被清除,而不是在表达式末尾。

在这种情况下,整个 while 块都是语句,而不仅仅是 let 模式匹配中的表达式。

迈克尔的回答基本上是正确的。可以在 Rust's reference regarding Place Expressions, Value Expressions and Temporary Lifetimes:

中找到更多详细信息

在第一个示例 (let job = ...) 中,MutexGuard 是临时的。临时生命周期在语句结束时结束。因此 MutexGuardlet job = ... 语句之后被删除。

在第二个示例 while let ... 中,MutexGuardwhile 表达式的 scrutinee 的一部分。这使得 MutexGuard 成为位置表达式上下文中值表达式的一部分。由于无法升级到 'static,因此整个 scrutinee 的生命周期是封闭块,而不是封闭语句。也就是说,MutexGuard 为整个 while let 块保留。