昨天在IRC中对此进行了一些讨论,这让我感到有些不满意。
问题是:
如何在结构上定义生命周期以限制其内容 只有与“本身”一样长寿的东西。
即。一种'自我的东西。
我最初的反应是:你做不到。
如果你创建一个struct Foo<'a&gt ;,那么与它相关的生命周期是从它包含的引用中推断出来的;除非结构包含对本身的引用(不可能),否则你不能拥有这种“自我生命”。
有一堆关于它的喋喋不休,最后我写了this playpen结果:
#[deriving(Show)]
struct Bar;
#[deriving(Show)]
struct Foo<'a> {
a:&'a Bar,
b:&'a Bar
}
fn factory<'a>(v1:&'a Bar, v2: &'a Bar) -> Foo<'a> {
return Foo {
a: v1,
b: v2
};
}
fn main() { // <---- Let's call this block lifetime 'one
let a = Bar;
let c = &a; // <-- C has lifetime 'one
{ // <------------ Let's call this block lifetime 'two
let b = Bar;
let mut foo1 = factory(c, c);
foo1.b = &b;
let mut foo2 = factory(&b, &b);
foo2.a = &a;
println!("{}", foo1);
println!("{}", foo2);
}
}
然而,我现在更困惑而不是更少。
所以,严格意义上说:
现在,我的困惑:
富&LT;'一&GT;表示'a是最小生命周期约束,可以包含在Foo实例中。
自'one&gt; '两,foo2应该能够包含一个&amp;'一个;这很有效。
自'两个&gt; '一,foo1应该不能够包含&amp;'两个b;然而'这是有效的。
为什么呢?
看来我的混淆是由于两种错误观念之一造成的;之一:
1)foo1的实例在面部Foo&lt;'two&gt;中,而不是Foo&lt;'one&gt;。
我不明白为什么会出现这种情况,因为它是在工厂制造的&lt;'&gt;其中&lt;'a&gt;是c的生命周期;这是'一个,不是'两个。在上面的例子中,c绝对没有办法和'两个'。在创建Foo的函数工厂中,生命周期''不可用。
2)结构生命周期不起作用,我理解它们的工作方式;即。在创建实例之后(例如,在移动中),在Foo实例上的'a a life的生命周期可以以某种方式改变。)
......但我不知道是哪一个。
答案 0 :(得分:5)
引用的生命周期参数是逆变:必要时,它们可以用更短的生命周期代替。
基本上,你已经错误地解决了这个问题。如果您有&'one Bar
,则无法为较短生命周期的值(例如此处为'two
)分配引用,否则当执行离开时,引用将悬空'two
范围。但是,如果您有&'two Bar
,则可以为具有更长生命周期的值(例如'one
和'static
)分配引用,因为引用将超出范围之前指称确实。
为什么你的程序会编译?编译器不仅仅使用来自factory
的调用的信息来选择适当的生命周期; it also uses information from the assignments。 &a
的类型为&'one Bar
,&b
的类型为&'two Bar
。由于'two
在'one
之后开始并在'one
之前结束,因此编译器可以强制 &'one Bar
到&'two Bar
。在面向对象的术语中,&'one Bar
是 &'two Bar
(&'one Bar
是&'two Bar
的子类型)。就像在Java中一样,您可以将String
作为参数传递给期望Object
的函数。只是因为子类型关系是生命周期的另一种方式。
这意味着我们找到了&a
和&b
:&'two Bar
的常见类型。因此,编译器会在调用'two
时为'a
推断factory
。
请注意foo2
的类型在作业时不会发生变化;值的类型始终是静态的。