【发布时间】:2019-11-27 11:39:22
【问题描述】:
我的许多函数都有以下模式:
use std::sync::{Arc, Mutex};
struct State {
value: i32
}
fn foo(data: Arc<Mutex<State>>) {
let state = &mut data.lock().expect("Could not lock mutex");
// mutate `state`
}
&mut *data.lock().expect("Could not lock mutex") 一遍又一遍地重复,所以我想将它重构为一个函数,以便编写类似的东西
let state = get_state(data);
我尝试了以下方法:
fn get_state(data: &Arc<Mutex<State>>) -> &mut State {
&mut data.lock().expect("Could not lock mutex")
}
编译失败:
错误:无法返回引用临时值的值
这让我相信data.state.lock().expect("...") 按价值返回。但是,我可以看到通过多次foo 调用on this playground 改变了状态。
这是怎么回事?为什么我看似简单的重构编译失败?
编辑:
我希望以下内容也能正常工作:
fn get_state<'a>(data: &'a Arc<Mutex<State>>) -> &'a mut State {
let state: &'a mut State = &mut data.lock().expect("Could not lock mutex");
state
}
但它失败了:
|
12 | fn get_state<'a>(data: &'a Arc<Mutex<State>>) -> &'a mut State {
| -- lifetime `'a` defined here
13 | let state: &'a mut State = &mut data.lock().expect("Could not lock mutex");
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'a`
14 | state
15 | }
| - temporary value is freed at the end of this statement
为什么从lock 返回的内容的生命周期与data 参数之一不匹配?
【问题讨论】:
-
lock()返回MutexGuard而不是值本身。您可以访问存储在其中的值,因为它实现了Deref和DerefMut,但您仍然在引用互斥锁。当互斥锁超出范围时,您的引用将指向已释放的内存,因此 rust 阻止了这种情况的发生。 (请记住,一旦互斥锁超出范围,互斥锁将被释放!!!) PS:与其将.expect()隐藏在另一种方法中,不如正确处理错误情况 -
@SvetlinZarev:这是有道理的。假设我不使用
expect,我确实处理了错误,但每个函数的错误处理都是相同的。同样,在这种情况下如何避免重复?我能想到的唯一方法是高阶函数 - 这是惯用的吗? -
我真的不能说什么是惯用的,但我的观察是,常见的重复性任务通常由宏处理。
-
如果将结果类型从
&mut State更改为MutexGuard<State>,重构将是有效的。 @Svetlin:我想这就是你想要表达的意思吗? -
我的意思是不能绕过
MutexGuard。如果 OP 返回 MutexGuard -> 那么应该可以。
标签: rust refactoring mutex borrowing