根据我的理解,在互斥锁上获得锁,然后立即在受保护的 struct 上调用函数,而不为互斥锁声明单独的变量,一旦函数调用完成,就会释放该保护.
我的问题是,在循环声明中获取锁时是否也是这样:
for ele in mtx.lock().await.clone() {
// do something requiring lock on mtx
}
这里的期望是,一旦clone
调用完成,mtx上的锁就会被释放,并且可以在循环中重新获得.是这样吗?如果不是,为什么不是这样?
根据我的理解,在互斥锁上获得锁,然后立即在受保护的 struct 上调用函数,而不为互斥锁声明单独的变量,一旦函数调用完成,就会释放该保护.
我的问题是,在循环声明中获取锁时是否也是这样:
for ele in mtx.lock().await.clone() {
// do something requiring lock on mtx
}
这里的期望是,一旦clone
调用完成,mtx上的锁就会被释放,并且可以在循环中重新获得.是这样吗?如果不是,为什么不是这样?
不,事实并非如此.迭代器表达式中创建的临时变量将一直存在到for循环结束,互斥锁保护只会在循环结束后删除.
临时表通常在语句末尾删除.您可以在documentation on temporary scopes中查看完整规则:
除了生存期扩展之外,表达式的临时作用域是包含该表达式的最小作用域,并且是以下作用域之一:
- 整个功能体.
- 一个声明.
if
、while
或loop
表达式的主体.if
表达式的else
块.if
或while
表达式或match
保护的条件表达式.- 匹配臂的表达式.
- 惰性布尔表达式的第二个操作数.
这些规则涵盖了许多微妙的情况,所以很难简单地总结一下为什么语言是这样设计的.特别是对于For循环,如果在迭代器表达式中创建的临时对象会立即被删除,这将非常恼人,因为这样会导致borrow 判断器错误:
for x in my_vec.iter().filter(|&&y| y != 0) {
...
}
如果编译器只保留迭代器表达式的result,那么返回my_vec.iter()
的迭代器将立即被删除,这当然不是所希望的.