我最近一直在从事我的第一个 Rust 项目,但遇到了障碍。我正在使用 HashMap
将 String
映射到 AtomicUsize
整数。 HashMap
受 RwLock
保护以允许并发访问。我希望能够返回对 HashMap
中的 AtomicUsize
值的引用,但是如果我尝试在 RwLockWriteGuard 的生命周期之后将这些引用返回给调用者
我收到一个错误,提示 借用的值没有足够长的时间
。我在下面复制了一个最小的例子,并将相同的例子放在 Rust Playground 上 here .
use std::collections::HashMap;
use std::sync::RwLock;
use std::sync::atomic::{AtomicUsize, Ordering};
struct Bar {
val: AtomicUsize
}
impl Bar {
pub fn new() -> Self {
Bar { val: AtomicUsize::new(0) }
}
}
struct Foo {
map: RwLock<HashMap<String, Bar>>
}
impl Foo {
pub fn get(&self, key: String) -> &Bar {
self.map.write().unwrap().entry(key).or_insert(Bar::new())
}
}
fn main() {
let foo = Foo {map: RwLock::new(HashMap::new())};
let bar = foo.get("key".to_string());
}
我得到的错误发生在线路上:
self.map.write().unwrap().entry(key).or_insert(Bar::new())
而且是因为借来的值不够长寿。我读过其他一些讨论这个错误的帖子,这个 one特别是特别相关。读完之后,我可以了解到从互斥体返回的值的生命周期必须小于互斥体的生命周期,这似乎完全排除了我正在尝试做的事情。我明白为什么这应该是不可能的,因为如果我们有一个指向 Hashmap 的指针,而另一个将值插入到互斥锁中导致它被调整大小,那么我们将有一个悬空指针。
那么,我的问题是双重的。首先,我只是很好奇我是否正确理解了问题,或者是否还有其他原因导致我被禁止做我想做的事情?我的第二个问题是,如果没有 Box
原子整数并将它们存储在 HashMap
中,是否有另一种方法可以完成我正在尝试做的事情?这种方法似乎对我有用,因为我们可以返回一个指向始终有效的 Boxed
值的指针。然而,这种方法似乎效率低下,因为它需要额外的指针间接层和额外的分配。谢谢!
最佳答案
你是正确的,你不能返回对比 MutexGuard
还长的东西的引用,因为这可能会导致悬空指针。
不过,将内容包装在 Box
中也无济于事! Box
是一个拥有的指针,除了重定向之外,就引用生命周期而言,它的行为类似于包含的值。毕竟,如果您返回对它的引用,其他人可能会从 HashMap
中删除它并取消分配它。
根据你想用引用做什么,我可以想到几个选项:
不是将值
Box
,而是将它们包装在Arc
中。从HashMap
获取数据时,您将克隆Arc
,多个引用可以同时存在。您还可以将
MutexGuard
与引用一起返回;见this question ,如果您只想对值进行操作然后相对较快地删除引用,这会很好用。这将保持互斥量直到您完成它。
关于hashmap - 试图从 RwLock 返回引用, "borrowed value does not live long enough"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40299671/