How can I get this to work? It is a contrived example but doesn't compile. This is the error:
return map.get(&key).unwrap();
| ---^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `map` is borrowed here
How can I fix this the right way? Thanks.
use std::sync::{RwLock};
use std::collections::HashMap;
struct Outer
{
outer : RwLock<HashMap<String, String>>
}
impl Outer
{
fn new() -> Self
{
return Self {
outer : RwLock::new(HashMap::new())
}
}
fn add(&mut self, key : String, value : String) -> ()
{
let mut map = self.outer.write().unwrap();
map.insert(key, value);
}
fn get(&self, key : String) -> &str
{
let map = self.outer.read().unwrap();
return map.get(&key).unwrap();
}
}
Could you rewrite that as:
let t = map.get(&key).unwrap();
return t;
?
I am also confused by the compiler error and want to see if the error is due to unwrap() or due to the return.
jjpe
September 21, 2021, 6:31am
3
Why even have the RwLock
there at all?
I don't see any attributes on the struct, so what is the RwLock
used for?
alice
September 21, 2021, 7:27am
4
The problem is that the call to read
returns a value of type RwLockReadGuard
. The existence of this type is what lets you access the RwLock
contents, and when the guard goes out of scope, your lock of the RwLock
is released, and it's unsafe to access its contents after that. The error is because you are trying to do exactly that.
4 Likes
So how do I fix this? Typically, in other languages you grab a read lock get a reference to what is in the map and hand it out. How do I achieve this in this situation. Thanks
alice
September 21, 2021, 1:57pm
6
You can return the RwLockReadGuard
from the function.
alice
September 21, 2021, 2:02pm
7
There are also some other options. For example, you could clone the value before returning it:
fn get(&self, key: &str) -> String {
let map = self.outer.read().unwrap();
map.get(key).unwrap().clone()
}
Another option is to have the caller pass in a function which runs while the value is locked. That looks like this:
fn with_read_lock<F, T>(&self, key: &str, function: F) -> T
where
F: FnOnce(&str) -> T,
{
let map = self.outer.read().unwrap();
function(map.get(key).unwrap())
}
You use it like this:
fn main() {
let outer = Outer::new();
outer.add("foo".to_string(), "bar".to_string());
outer.with_read_lock("foo", |value| {
println!("{}", value);
});
}
Unrelated, but when you use an RwLock
, you shouldn't mark the modification methods as &mut self
. You can mark them &self
without issue.
2 Likes
This looks like a duplicate of your previous thread. Were you able to try any of the suggestions there?
How can I fix this? Of course this is a contrived example but matches a use-case relatively closely. I get the error "returns a value referencing data owned by the current function". I understand the error but how do I fix it?
struct Inner
{
inner : String
}
struct Outer
{
outer : RwLock<Inner>
}
impl Outer
{
fn new() -> Self
{
return Self {
outer : RwLock::new(Inner{inner : "hello".into()})
}
}
fn get_a_ref(&self) -> &str
{
…
1 Like
Ah you give me too much credit. I am still trying to wrap my head around those suggestions. I am further simplifying things for myself and will get back to that soon. Thanks
system
Closed
December 20, 2021, 2:26pm
10
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.