如果我写下面的代码,我会得到error[E0309]: the parameter type 'T' may not live long enough.
struct Function<T> {
f: fn() -> T,
}
struct FunctionRef<'f, T> {
f: &'f Function<T>,
}
Run Code Online (Sandbox Code Playgroud)
这修复了错误:
struct FunctionRef<'f, T: 'f> {
f: &'f Function<T>,
}
Run Code Online (Sandbox Code Playgroud)
但是,就我所知,T不受生命的束缚'f.实际上,是运行T类型函数时创建的新对象fn () -> T.
我在哪里错过了什么?
简短回答:您需要,T: 'f因为T可能包含保存引用的字段并且fn() -> T与 协变T。
简化事情可能有助于理解......
暂时用 代替fn() -> T,T因为对我来说,解释生命周期中发生的事情更简单。请参阅下面的注释,了解为什么此替换不会更改与生命周期相关的错误。
struct Function<T> {
f: T,
}
struct FunctionRef<'f, T> {
f: &'f Function<T>,
}
Run Code Online (Sandbox Code Playgroud)
这会导致同样的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>,
}
Run Code Online (Sandbox Code Playgroud)
您需要将生命周期限制'a为至少与生命周期一样长'f,否则将违反内存安全规则。
f: T我已经考虑了相当于的情况,f: fn() -> T因为这种类型构造函数是协变的T。
fn() -> T要理解is covariant over的含义T,请考虑以下结构:
struct Foo<'a> {
v: &'a i32
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,可以安全地分配给v生命周期“大于”的值'a,例如:
let ref_value: &'static i32 = &100;
let foo = Foo { v: ref_value};
Run Code Online (Sandbox Code Playgroud)
现在同样适用于以下结构:
struct Function<'a> {
f: fn() -> &'a i32
}
Run Code Online (Sandbox Code Playgroud)
该字段需要一个返回outlive 的f函数。&i32'a
在这种情况下,传递一个返回具有“更大”生命周期的函数是安全的&i32,例如:
fn my_f() -> &'static i32 {
&100
}
fn main() {
let foo = Function { f: my_f};
}
Run Code Online (Sandbox Code Playgroud)
这背后有相当多的类型理论,详细解释请参见nomicom 。