结构的生命周期如何在Rust中起作用?

时间:2014-12-23 00:55:09

标签: rust lifetime

昨天在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);
  }
}

然而,我现在更困惑而不是更少。

所以,严格意义上说:

  • c有'一个
  • &amp; b有'两个
  • 'static&gt; '一个&gt; '两个(即'两个以'一个为界)。
  • foo1有'一个
  • 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的生命周期可以以某种方式改变。)

......但我不知道是哪一个。

1 个答案:

答案 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的类型在作业时不会发生变化;值的类型始终是静态的。