我最近一直在研究我的第一个Rust项目,但遇到了障碍。我正在使用HashMap
映射String
到AtomicUsize
整数。 HashMap
受RwLock
保护,以允许并发访问。我希望能够在AtomicUsize
中返回对HashMap
值的引用,但是如果我尝试在RwLockWriteGuard
的生命周期之后将这些引用返回给调用者,则会收到错误消息borrowed value does not live long enough
。我已经在下面复制了一个最小的示例,并将相同的示例放在Rust操场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
值的指针,该值始终有效。然而,似乎这种方法效率低下,因为它需要一个额外的指针间接层和一个额外的分配。谢谢!
答案 0 :(得分:5)
你是正确的,你不能返回一个比MutexGuard
更长的东西的引用,因为这会导致一个可能悬空的指针。
将内容包装在Box
中无济于事! Box
是一个拥有的指针,除了参考生命周期之外,重定向的行为类似于包含的值。毕竟,如果您返回对它的引用,其他人可能会将其从HashMap
中删除并取消分配。
根据您对参考的要求,我可以考虑几个选项:
而不是Box
值,将它们包装在Arc
中。从Arc
获取时,您将克隆HashMap
,并且可以同时存在多个引用。
您还可以将MutexGuard
与参考一起返回;请参阅this question,如果您只想对该值进行操作,然后相对较快地删除该引用,这将很有效。这将保持互斥锁持续直到你完成它。