Нет разницы между замыканием и прямым вызовом функции: это просто вопрос вывода типа.
замыкание, которое компилируется:
let _v = optional_values.unwrap_or_else(|| default_values());
let _v = optional_values.unwrap_or_else(|| -> & [u32] {default_values()});
замыкание, которое не компилируется:
let _v = unwrap_or_else(optional_values, || -> &'static [u32] {default_values()});
функция, которая компилирует:
let _v = unwrap_or_else(optional_values, default_values as fn() -> &'static _);
функция, которая не компилируется:
let _v = unwrap_or_else(optional_values, default_values);
Небольшое объяснение
Рассмотрим этот эквивалентный код:
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()
}
}
следующий фрагмент:
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);
}
не удается:
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
Взгляд со стороны мономорфизации: при условии, что
компилятор делает вывод, что T
разрешается в конкретный тип &'static [u32]
,
и предположим, что полученный код выглядит примерно так:
fn unwrap_or_else_u32_sl_fn_u32_sl(slf: Option<&'static [u32]>,
f: fn() -> &'static [u32]) -> &'static [u32] {
...
}
тогда приведенная выше мономорфизация объясняет ошибку:
slf
значение равно optional_values
: Option<&'a [u32]>
, который недостаточно жив и явно не может быть разыгран, потому что он не удовлетворяет требованию 'static
срока службы.
Если вы напишите:
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()});
Компилируется: теперь время жизни возвращаемого типа совместимо с временем жизни optional_values
.
Наконец, я не могу объяснить, почему, но факты показывают, что приведение as fn() -> &'static _
помогает компилятору быть уверенным в том, что время жизни развязки, связанное с optional_values
и default_values
, безопасно.