I've been working on my first Rust project recently but have hit a snag. I am using a HashMap
mapping String
s to AtomicUsize
integers. The HashMap
is protected by a RwLock
to allow for concurrent access. I would like to be able to return references to AtomicUsize
values in the HashMap
, however if I try to return these references to the caller past the lifetime of the RwLockWriteGuard
I get an error that borrowed value does not live long enough
. I've reproduced a minimal example below and put the same example on the 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());
}
The error I get occurs on the line:
self.map.write().unwrap().entry(key).or_insert(Bar::new())
And is because the borrowed value does not live long enough. I've read a few other posts that discuss this error, this one in particular was especially relevant. After reading it over, I can gather that a value returned from a mutex must have a lifetime less than that of the mutex, which would seem to rule out completely what I'm trying to do. I can see why this should be impossible, because if we have a pointer into the Hashmap and another inserts values into the mutex which cause it to be resized, then we will have a dangling pointer.
My question, then, is twofold. Firstly, I'm just curious if I understand the problem correctly or if there is another reason why I'm disallowed from doing what I tried to do? And my second question is if there is perhaps another way to accomplish what I am trying to do without Box
the atomic integers and storing those in the HashMap
? Such an approach seems like it should work to me because we can return a pointer to the Boxed
value which would always be valid. However it seems like this approach would be inefficient because it would require an extra layer of pointer indirection and an extra allocation. Thanks!