I've been writing some rust code, and I hit a weird (to me, at least) case that lead to my program failing due to lifetimes not being handled as I would expect. Here's a minimal example that reproduces my issue:
fn foo() -> &'static str { "foo" }
pub fn bar_good<'a>(b: Option<&'a str>) -> &'a str {
b.unwrap_or_else(|| foo())
}
pub fn bar_bad<'a>(b: Option<&'a str>) -> &'a str {
b.unwrap_or_else(foo)
}
Playground link (note: the explicit lifetimes aren't required, but I think it makes this post clearer)
My intuition says that both bar_good
and bar_bad
functions should have the same behavior. For either one, we have an Option<&'a str>
, and we call Option<&'a str>::unwrap_or_else
, which expects something implementing FnOnce() -> &'a str
as its argument. In both cases, I give it a function that returns a &'static str
, and because functions are covariant on their output, this satisfies the requirement and the expression evaluates to &'a str
.
With the bar_good
function, this intuition is met, and everything works as I expect. However, with the bar_bad
function, something doesn't match my intuition and I get the error:
error[E0521]: borrowed data escapes outside of function
--> src/lib.rs:8:5
|
7 | pub fn bar_bad<'a>(b: Option<&'a str>) -> &'a str {
| -- - `b` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
8 | b.unwrap_or_else(foo)
| ^^^^^^^^^^^^^^^^^^^^^
| |
| `b` escapes the function body here
| argument requires that `'a` must outlive `'static`
For more information about this error, try `rustc --explain E0521`.
It seems like the fn() -> &'static str
being passed as the argument to Option::unwrap_or_else
convinces the lifetime checker that I must be calling Option<&'static str>::unwrap_or_else
, and it rejects the code because 'a
does not outlive 'static
, not seeing that it could just loosen the lifetime requirement to 'a
and the whole function now passes.
What is going on in the Rust compiler against my intuition that's making this program fail to check the lifetimes? Clearly, something about my intuition must mismatch with the real behavior, but I don't know what.