There is no difference between a closure and a direct function call: It is just a matter of type inference.
closure that compiles:
let _v = optional_values.unwrap_or_else(|| default_values());
let _v = optional_values.unwrap_or_else(|| -> & [u32] {default_values()});
closure that not compiles:
let _v = unwrap_or_else(optional_values, || -> &'static [u32] {default_values()});
function that compiles:
let _v = unwrap_or_else(optional_values, default_values as fn() -> &'static _);
function that not compiles:
let _v = unwrap_or_else(optional_values, default_values);
A litte bit of explanation
Consider this equivalent code:
fn default_values() -> &'static [u32] {
static VALUES: [u32; 3] = [1, 2, 3];
&VALUES
}
fn unwrap_or_else<T, F>(slf: Option<T>, f: F) -> T where
F: FnOnce() -> T, {
match slf {
Some(t) => t,
None => f()
}
}
the following snippet:
fn main() {
let values: [u32; 3] = [4, 5, 6];
let optional_values: Option<&[u32]> = Some(&values);
let _v = unwrap_or_else(optional_values, || -> &'static [u32] {default_values});
// the above throws the same error of:
//let _v = unwrap_or_else(optional_values, default_values);
}
fails:
error[E0597]: `values` does not live long enough
--> src/main.rs:18:48
|
18 | let optional_values: Option<&[u32]> = Some(&values);
| ^^^^^^^
| |
| borrowed value does not live long enough
| cast requires that `values` is borrowed for `'static`
...
27 | }
| - `values` dropped here while still borrowed
Look from the monomorphization side: assuming that
the compiler infers that T resolves to the concrete type &'static [u32],
and supposing that the produced code is something like:
fn unwrap_or_else_u32_sl_fn_u32_sl(slf: Option<&'static [u32]>,
f: fn() -> &'static [u32]) -> &'static [u32] {
...
}
then the above monomorphization explains the error:
slf value is optional_values: an Option<&'a [u32]> that does not live enough and clearly cannot be cast because it does not satisfies the 'static lifetime requirement.
If you write:
let _v = unwrap_or_else(optional_values, || default_values());
// the same, expliciting the return type:
let _v = unwrap_or_else(optional_values, || -> & [u32] {default_values()});
It compiles: now the lifetime of the return type is compatible with the optional_values lifetime.
Finally, I'm not able to explain why, but the evidence shows that the cast as fn() -> &'static _ helps the compiler to be sure that decoupling lifetimes bound to optional_values and default_values is safe.