Краткий ответ: вам нужно T: 'f
, потому что T
может содержать поле, содержащее ссылки, а fn() -> T
является ковариантным по отношению к T
.
Чтобы упростить вещи, может помочь понять ...
На мгновение замените fn() -> T
на T
, потому что для меня проще объяснить, что происходит с жизнями.
См. Примечание ниже, почему при такой замене не изменяется ошибка, связанная с временем жизни.
struct Function<T> {
f: T,
}
struct FunctionRef<'f, T> {
f: &'f Function<T>,
}
Это приводит к той же самой ошибке error[E0309]: the parameter type 'T' may not live long enough
.
FunctionRef
экземпляры не могут пережить ссылку, которая содержится в поле f
:
вы объявляете общий параметр времени жизни 'f
в угловых скобках, а затем используете 'f
в качестве аннотации
внутри структуры тела. См. Также книгу .
Но FunctionRef::f
зависит от параметра типа T
. Явное ограничение T: 'f
гарантирует, что T
экземпляров
не переживает ссылки, удерживаемые T
, а FunctionRef
не переживает FunctionRef::f
.
Если это может помочь понять, замените универсальный T
конкретным Foo
типом:
struct Foo<'a> {
n: &'a i32,
}
struct FunctionRef<'f, 'a: 'f> {
f: &'f Foo<'a>,
}
Необходимо ограничить время жизни 'a
, чтобы оно действовало по крайней мере столько, сколько 'f
время жизни, в противном случае правила безопасности памяти были бы нарушены.
Примечание
Я рассмотрел случай f: T
эквивалент f: fn() -> T
, потому что такой конструктор типов ковариантен над T
.
Чтобы понять, что значение fn() -> T
является ковариантным по отношению к T
, рассмотрим следующую структуру:
struct Foo<'a> {
v: &'a i32
}
В этом случае безопасно присвоить v
значение со временем жизни "больше", чем 'a
, например:
let ref_value: &'static i32 = &100;
let foo = Foo { v: ref_value};
Теперь то же самое верно для следующей структуры:
struct Function<'a> {
f: fn() -> &'a i32
}
Поле f
ожидает функцию, которая возвращает &i32
, который переживет 'a
.
В этом случае безопасно передать функцию, которая возвращает &i32
с «большим» временем жизни, например:
fn my_f() -> &'static i32 {
&100
}
fn main() {
let foo = Function { f: my_f};
}
За этим стоит довольно много теорий типов, подробное объяснение см. В терминологии .