如果我在下面编写代码,则会得到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>,
}
这可以修复错误:
struct FunctionRef<'f, T: 'f> {
f: &'f Function<T>,
}
但是,据我所知,T
不受生存期'f
的限制。实际上,T
是运行类型fn () -> T
的函数时创建的新对象。
我在哪里缺少什么?
答案 0 :(得分:4)
简短的回答:您需要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
作为注释
在结构体内。另请参见book。
但是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
的{{1}}的函数。
在这种情况下,可以安全地返回一个返回“ 'a
”且寿命更长的函数,例如:
&i32
背后有很多类型理论,see the nomicom进行了详细说明。