结构参考参数化函数的生命周期错误

Oli*_*ier 6 rust

如果我写下面的代码,我会得到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.

我在哪里错过了什么?

att*_*ona 4

简短回答:您需要,T: 'f因为T可能包含保存引用的字段并且fn() -> T与 协变T

简化事情可能有助于理解......

暂时用 代替fn() -> TT因为对我来说,解释生命周期中发生的事情更简单。请参阅下面的注释,了解为什么此替换不会更改与生命周期相关的错误。

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 。