为什么 'if let' 使用 Mutex 会阻止执行?

Why does 'if let' block the execution with usage of Mutex?

我在使用 Mutex

时遇到了这种死锁情况

包含Mutex类型字段的结构如下:

struct MyStruct {
    inner_map: Arc<Mutex<HashMap<i32, Vec<i32>>>>,
}

我已经通过锁定 Mutex 访问了这个内部映射:

impl MyStruct {
    fn test_lock(&self, key: &i32) {
        let my_option = self.inner_map.lock().unwrap().remove(key);
        if let Some(my_vec) = my_option {
            for _inner_val in my_vec {
                self.inner_map.lock().unwrap();
                println!("Passed test_lock1");
            }
        }
    }
}

这工作正常,没有死锁,因为我从 HashMap 中删除了值并从 HashMap

中获得了所有权

与 test_lock 非常相似的功能,唯一不同的是它不是将删除的值声明为 my_option 变量,而是在 if let 调用和 在这种情况下会导致死锁:

impl MyStruct{
    // Why this function goes to deadlock since remove gets the ownership of the data?
    fn test_lock2(&self, key: &i32) {
        if let Some(my_vec) = self.inner_map.lock().unwrap().remove(key) {
            for _inner_val in my_vec {
                self.inner_map.lock().unwrap();
                println!("Passed test_lock2");
            }
        }
    }
}

声明变量会改变这种行为的主要原因是什么?

Playground

The lock is released when the LockResult goes out of scope.

现在我们必须深入scope rules regarding this temporary value

临时值的范围是封闭语句。

在第一个片段中,这意味着锁在进入 if/let 构造之前超出范围。没有死锁。

但是 if let 条件中临时值的范围是整个 if/let 构造:

the lifetime of temporary values is typically

  • the innermost enclosing statement; the tail expression of a block is considered part of the statement that encloses the block, or
  • the condition expression or the loop conditional expression if the temporary is created in the condition expression of an if or in the loop conditional expression of a while expression.

When a temporary value expression is being created that is assigned into a let declaration, however, the temporary is created with the lifetime of the enclosing block instead, as using the enclosing let declaration would be a guaranteed error (since a pointer to the temporary would be stored into a variable, but the temporary would be freed before the variable could be used)

在第二个片段中,锁的作用域覆盖了整个 if/let 结构。

这解释了为什么当您尝试在循环中再次锁定时第一个锁仍然处于活动状态。