Suppose you have a struct Big
and a function get_big
that fetches a Big
from a map, ideally borrowed. If it isn't in the map, get_big
should return a fallback value of Big
. Values in Big
can be large enough that they should not be needlessly cloned, but the fallback value is cheap to construct or clone. My question is about the best way to implement get_big
, especially choosing a return type.
The obvious (to me) approach, which returns &Big
, fails:
// Question is meant for general Big, but here's an example.
struct ExampleBig { members: Vec<String> }
fn get_big(map: &BTreeMap<i32, ExampleBig>, key: i32) -> &ExampleBig {
if let Some(found_s) = map.get(&key) {
found_s
} else {
// ERROR: Can't borrow a temp value.
&ExampleBig { members: vec![] }
}
}
Here are the alternatives and fixes I could come up with:
- Return
Big
, cloning in the found-in-map case, which as mentioned above is not ideal here. - Return
Option<&Big>
and repeat.unwrap_or(&fallback)
at every callsite. (Sadly, the fallback is not always the default value.) - Return
&Big
. On the struct with the map, store an owned fallback value in a separate field, and return references to it. (This is what I have been doing.) - Return
&Big
. Lazily create an owned fallbackBig
value with one of theOnceCell
patterns, and return references to it.- I don't know a good way to do this if
Big
is generic, which it is in my case.
- I don't know a good way to do this if
In my case, this is just trying to squeeze out some extra convenience/ergonomics from typical map usage, rather than an essential need. Returning Option<&Big>
is probably the most idiomatic choice. The question is being asked more out of surprise that I couldn't come up with a nice solution.
I am interested to hear if there's a better way I didn't think of.