在Rust中,结构的终身约束是如何工作的?

问题描述 投票:4回答:1

昨天在IRC里有一些关于这个问题的讨论,让我隐隐感到不满。

问题是。

你如何定义一个结构的生命周期 来限制它的内容只和 "它本身 "一样长的东西。

即一个 'self 种东西。

我最初的反应是:不能。

如果你创建一个结构 Foo<'a>的引用来推断与它相关的寿命;除非结构体包含对 本身 (不可能),你不可能有这样的 'self 一生。

有一大堆人在议论,最后我写了 这个游乐场 因此,。

#[derive(Debug)]
struct Bar;

#[derive(Debug)]
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 已经 'one
  • &b'two
  • 'static > 'one > 'two (即: 'two 边界为 'one).
  • foo1'one
  • foo2'two

现在,我的困惑。

Foo<'a> 表示 'a最小寿命界限 的实例所能包含的 Foo.

  • 由于 'one > 'two, foo2 应能包含一个 &'one a;这就可以了。

  • 由于 'two > 'one, foo1 容得下 &'two b;然而,这样做是可行的。

为什么呢?

看来我的困惑是由两种误解之一造成的;要么。

  1. 要么是... foo1 其实 Foo<'two>,不 Foo<'one>.

    我不明白为什么会是这样,因为它是在 factory<'a> 哪儿 <'a> 是一生的 c;这就是 'one,不 'two. 绝对没有办法 c 可以 &'two 在上面的例子中。寿命 'two 在功能工厂中是不可用的,其中 Foo 是创建的。

2)结构寿命并不是我所理解的工作方式,即一生中的 'a 关于 Foo 实例创建后,可以以某种方式改变(例如,在移动时?

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

rust lifetime
1个回答
7
投票

引用上的寿命参数是 共变:它们可以用以下词语代替:"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"、"我"。较短 必要的时候,一辈子。

基本上,你把它弄错了。当你有一个 &'one Bar的值,不能用 较短 辈子 'two 这里),否则当执行离开 'two 范围。然而,当你有一个 &'two Bar您可以将一个引用分配给一个寿命较长的值(如 'one'static),因为在引用之前,引用就会超出范围。

为什么你的程序会被编译? 编译器并不仅仅使用来自调用 factory 以选择适当的寿命。它还使用来自分配的信息. &a 有类型 &'one Bar&b 有型 &'two Bar. 因为 'two 开始于 'one 并在 'one,编译器可以 逼迫 a &'one Bar&'two Bar. 用面向对象的术语来说,一个 &'one Bar 是一个 &'two Bar (&'one Bar&'two Bar). 就像在Java中,你可以通过一个叫 String 作为一个函数的参数,该函数期待一个 Object. 在Java中,类的子类型关系是子类是其父类的子类型,但寿命的子类型关系是较长的寿命是较短的寿命的子类型。

这意味着,我们已经找到了一个共同的类型,即为 &a&b: &'two Bar. 因此,编译器推断出 'two 对于 'a 在呼叫中 factory.

请注意 foo2 在赋值时不会改变,一个值的类型总是静态的。

© www.soinside.com 2019 - 2024. All rights reserved.