How can I return a default value from an Option<&String>?
This is my sample/minimal code:
fn main() {
let map = std::collections::HashMap::<String, String>::new();
let result = map.get("").or_else(|| Some("")).unwrap(); // <== I tried lots of combinations
println!("{}", result);
}
I know I could do something like this...
let value = match result {
Some(v) => v,
None => "",
};
... but I want to know if it is possible to implement it in a one-liner with or_else or unwrap_or_else?
(It is important to make the default value lazy, so it does not get computed if it is not used)
These are some of the compiler suggestions I tried (I can put them all because SO won't allow me):
7 | let result = map.get("").or_else(|| Some("") ).unwrap();
| ^^ expected struct `String`, found `str`
.
7 | let result = map.get("").or_else(|| Some(&"".to_string()) ).unwrap();
| ^^^^^^--------------^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
.
7 | let result = map.get("").or_else(|| Some(String::new()) ).unwrap();
| ^^^^^^^^^^^^^
| |
| expected `&String`, found struct `String`
|
help: consider borrowing here: `&String::new()`
.
7 | let result = map.get("").or_else(|| Some(&String::new()) ).unwrap();
| ^^^^^^-------------^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
. and also
6 | let result = map.get("").unwrap_or_else(|| ""); // I tried lots
| ^^ expected struct `String`, found `str`
|
= note: expected reference `&String`
found reference `&'static str`
If you really need a &String as the result, you may create a String for the default value with lifetime that's long enough.
fn main() {
let map = std::collections::HashMap::<String, String>::new();
let default_value = "default_value".to_string();
let result = map.get("").unwrap_or(&default_value);
println!("{}", result);
}
If the default value is a compile-time fixed value, the allocation of default_value can be avoided by using &str instead.
fn main() {
let map = std::collections::HashMap::<String, String>::new();
let result = map.get("")
.map(String::as_str)
.unwrap_or("default_value");
println!("{}", result);
}
How can I return a default value from an Option<&String>?
It's not trivial because as you've discovered ownership gets in the way, as you need an actual String to create an &String. The cheap and easy solution to that is to just have a static empty String really:
static DEFAULT: String = String::new();
fn main() {
let map = std::collections::HashMap::<String, String>::new();
let result = map.get("").unwrap_or(&DEFAULT); // <== I tried lots of combinations
println!("{}", result);
}
String::new is const since 1.39.0, and does not allocate, so this works fine. If you want a non-empty string as default value it's not as good a solution though.
The cleaner and more regular alternative is to "downgrade" (or upgrade, depending on the POV) the &String to an &str:
let result = map.get("").map(String::as_str).unwrap_or("");
or
let result = map.get("").map(|s| &**s).unwrap_or("");
it's really not like you're losing anything here, as &String is not much more capable than &str (it does offer a few more thing e.g. String::capacity, but for the most part it exists on genericity grounds e.g. HashMap::<K, V>::get returns an &V, so if you store a String you get an &String makes sense even though it's not always quite the thing you want most).
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