[英]Borrow data out of a mutex “borrowed value does not live long enough”
如何在互斥体中的数据上返回迭代器,互斥体本身包含在结构中。 编译器给出的错误是“借来的价值活得不够长”。
如何让值的生命周期扩展到外部作用域?
这是我试图实现的最小演示。
use std::sync::{Mutex, Arc};
use std::vec::{Vec};
use std::slice::{Iter};
#[derive(Debug)]
struct SharedVec {
pub data: Arc<Mutex<Vec<u32>>>,
}
impl SharedVec {
fn iter(& self) -> Iter<u32> {
self.data.lock().unwrap().iter()
}
}
fn main() {
let sv = SharedVec {
data: Arc::new(Mutex::new(vec![1, 2, 3, 4, 5]))
};
for element in sv.data.lock().unwrap().iter() { // This works
println!("{:?}", element);
}
for element in sv.iter() { // This does not work
println!("{:?}", element);
}
}
Rust 游乐场链接: http : //is.gd/voukyN
你不能完全按照你在这里写的方式来做。
Rust 中的互斥锁使用 RAII 模式来获取和释放,也就是说,当你调用它的相应方法时,你会获取一个互斥锁,它返回一个特殊的保护值。 当这个守卫超出范围时,互斥锁被释放。
为了使这种模式安全,Rust 使用其借用系统。 您只能通过lock()
返回的守卫访问互斥锁中的值,并且您只能通过引用来访问 - MutexGuard<T>
实现了Deref<Target=T>
和DerefMut<Target=T>
,因此您可以获得&T
或&mut T
出来吧。
这意味着您从互斥值中获得的每个值都必须将其生命周期与守卫的生命周期相关联。 但是,在您的情况下,您试图返回Iter<u32>
其生命周期参数与self
的生命周期相关联。 以下是iter()
方法的完整签名,没有生命周期参数省略,它的主体带有显式临时变量:
fn iter<'a>(&'a self) -> Iter<'a, u32> {
let guard = self.data.lock().unwrap();
guard.iter()
}
这里的寿命guard.iter()
结果是联系在一起的一个guard
,它是严格地小于'a
,因为guard
只活方法体的范围内。 这违反了借用规则,因此编译器因错误而失败。
当iter()
返回时, guard
被销毁,锁被释放,所以 Rust 实际上阻止了你犯真正的逻辑错误! C++ 中的相同代码会编译并且行为不正确,因为您将访问受保护的数据而不锁定它,至少会导致数据竞争。 又一次展示了 Rust 的力量:)
我认为如果没有围绕标准类型的讨厌的黑客攻击或样板包装,你将无法做你想做的事。 我个人认为这很好——你必须尽可能明确地管理你的互斥,以避免死锁和其他令人讨厌的并发问题。 而 Rust 已经让你的生活变得更加轻松,因为它通过借用系统强制不存在数据竞争,这正是保护系统行为如上所述的原因。
正如vladimir-matveev谈到的那样,返回值是不可能的,但是如果不是返回 iter,而是将它传递给要使用的函数,您几乎可以实现您的目标
impl SharedVec {
fn iter<R>(& self, func : impl FnOnce(Iter<'_,u32>) -> R) -> R {
let guard = self.data.lock().unwrap();
func(guard.iter())
}
}
这个功能是这样使用的!
sv.iter(|iter|{
for element in iter {
println!("{:?}", element);
}
});
这种类型的函数包装将。 必须对每种类型的迭代器重复。 但是,如果您最终这样做可能会更容易,在这种情况下,只需交出 mut 切片或 &mut sharedVec 而不是让闭包选择迭代方法。
此方法的工作方式与 return 不同,因为您永远不会释放锁,以防止多个线程同时写入数据!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.