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

Dou*_*oug 4 lifetime rust

昨天在IRC中对此进行了一些讨论,这让我感到有些模糊不满.

问题是:

如何在结构上定义生命周期以将其内容限制为仅与"本身"一样长的内容.

即一种'自我的东西.

我最初的反应是:你做不到.

如果你创建一个struct Foo <'a>,那么与它相关的生命周期是从它包含的引用中推断出来的; 除非结构包含对自身的引用(不可能),否则你不能拥有这种"自我生命".

有一堆关于它的喋喋不休,最后我写了这个围栏结果:

#[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);
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,我现在更困惑而不是更少.

因此,严格意义上的:

  • c有一个
  • &b有'两个
  • 'static>'one>'two(即'two'以'one'为界).
  • foo1有一个
  • foo2有'两个

现在,我的困惑:

Foo <'a>表示'a是Foo实例可以包含的最小生命周期限制.

  • 由于'one>'两个,foo2应该能够包含一个&'one a; 这很有效.

  • 由于'two>'一,foo1 应该包含''两个b; 然而'这是有效的.

为什么?

看来我的混淆是由于两种错误观念之一造成的; 之一:

1)foo1的实例是面对Foo <'two>,而不是Foo <'one>.

我不明白为什么会这样,因为它是在工厂生产的,其中<'a>是c的寿命; 这是'一个,不是'两个.在上面的例子中,c绝对没有办法.在创建Foo的函数工厂中,生命周期'2'不可用.

2)结构生命周期不起作用,我理解它们的工作方式; 即.一个Foo实例上的'a'生命周期可以在创建实例之后以某种方式改变(例如,在移动中?)

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

Fra*_*gné 5

参考文献的寿命参数是逆变的:必要时可以用更短的寿命代替它们.

基本上,你有错误的方法.如果有a &'one Bar,则无法为具有较短生命周期的值(例如'two此处)分配引用,否则在执行离开'two作用域时引用将悬空.但是,如果有a &'two Bar,则可以为具有更长生命周期的值(例如'oneand 'static)分配引用,因为引用将在引用之前超出范围.

你的程序为什么要编译?编译器不仅使用来自调用的信息factory来选择适当的生命周期; 它还使用来自作业的信息.&a有类型&'one Bar&b类型&'two Bar.因为'two'one之前和之后开始'one,编译器可以强制 a &'one Bar到a &'two Bar.在面向对象的术语中,a &'one Bar 是a &'two Bar(&'one Bar是其子类型&'two Bar).就像在Java中一样,你可以将一个String参数作为一个参数传递给一个期望的函数Object.只是因为子类型关系是生命周期的另一种方式.

这意味着我们找到了一个常见的类型:&a和.因此,编译器推断为在呼叫.&b&'two Bar'two'afactory

请注意,foo2分配时的类型不会改变; 值的类型始终是静态的.