I have a HashMap that uses a char
for the key and a struct
for the value.
The HashMap's get()
method will often be called with keys that are not in the HashMap, so I'd like to use unwrap_or()
on the returned Option to create a default struct
value. However, when I attempt to do so, the compiler throws the following error (with temp
being the default value that I'm attempting to return):
lib.rs:51:4: 51:8 error: `temp` does not live long enough
Here is a small reproducer:
struct Sample {
thing: i32
}
fn do_stuff() {
let map = HashMap::<char, Sample>::new();
let sample = map.get(&'a').unwrap_or({
let temp = Sample {
thing : 0
};
&temp
});
}
I have two questions:
temp
binding live longer?struct
when using an Option?For your precise scenario, you can do something like this:
use std::collections::HashMap;
struct Sample {
thing : i32
}
fn main() {
let map = HashMap::<char, Sample>::new();
let temp = Sample { thing : 0 };
let sample = map.get(&'a').unwrap_or(&temp);
}
Often, though, you want something more like this:
use std::collections::HashMap;
#[derive(Clone)]
struct Sample {
thing : i32
}
fn get_sample(map: &HashMap<char, Sample>) -> Sample
{
map.get(&'a').cloned().unwrap_or_else(|| {
Sample { thing : 0 }
})
}
If you really want to conditionally initialize and take the address of a local variable, it's possible, but can't be written using unwrap_or
or unwrap_or_else
:
use std::collections::HashMap;
struct Sample {
thing : i32
}
fn main() {
let map = HashMap::<char, Sample>::new();
let temp;
let sample = match map.get(&'a') {
Some(sample) => sample,
None => {
temp = Sample { thing : 0 };
&temp
}
};
}
Note that your question shows you have a root misunderstanding:
How do I return a new struct
But then your code says this:
&temp
That's a reference to a struct. The problem is that your struct only lives for the duration of the block passed as an argument to unwrap_or
. As soon as the block is over, any variables that aren't returned from the block are dropped, invalidating any references to them.
Is there a way to make the temp binding live longer?
There is one way to make a binding live longer: move where it is in code. If you move the creation of a variable earlier, its lifetime starts earlier. That's why Eli Friedman's first solution works.
If you change your code to return a struct instead of a reference, then that explains how the second solution works, and better matches how you are modeling the problem. You can't always go from a reference to a non-reference cheaply though, and sometimes it's not even possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With