31

我对多次浏览 Rust 文档的标记部分和关于子类型方差的维基百科文章感到愚蠢,却没有提高我对生命周期子类型关系的理解。

我想我只是习惯了“典型的 OOP 风格”子关系,例如“Cat <: Animal”,意思是“Cat 是 Animal 的子类型”,其中“S 是 T 的子类型”意味着“任何术语 S 都可以安全在预期 T 类型术语的上下文中使用”。到目前为止,一切都很好。

但这如何适用于生命周期?现在在 Rust 中定义的方式显然是 (*)

(#1) 'a <: 'b <=> 生命周期 a 不长于生命周期 b。

你可能会想“当然就是这个意思!” 可能是因为 <: 看起来类似于小于运算符,或者可能是因为“sub”让您想到子集,而较短的寿命肯定是较长寿命的一个子集。但是,如果'a 不长于'b,'a 真的是'b的子类型吗?让我们尝试应用 Wikipedia 对子类型关系的定义:

(#2) 'a <: 'b <=> 生命周期 a 可以安全地用于预期生命周期 b 的上下文中。

我的问题是我无法调和这一点。你如何从#2 到#1?因为对我来说,这似乎是一个矛盾...如果您期望某物至少在 b 内还活着,并且您的某物的生命期 a 比 b 短,那么您显然不能在某物的生命期为 b 的情况下使用它是必需的,可以吗?只是我,还是我们把一生的子类型关系弄错了?

编辑:(*) 根据#rustIRC 频道中的 Ms2ger,情况就是这样。它还符合Items迭代器中使用的逆变生命周期标记的文档。

Edit2:ConvariantLifetime 和 CovariantLifetime 标记已被删除。我们现在在标记模块中有PhantomData一个替代品。

4

1 回答 1

5

免责声明:我不完全是 CS 大师,所以这个答案将集中在实际概念上,我什至不会尝试将它与理论概念联系起来,以免我把事情弄得一团糟。

我认为问题在于试图将子类型概念应用于不是类型的东西。

  • 'a是一生
  • &'a T是一种类型

您可以比较&'a T&'b U查看它们是否遵循子类型关系,但您无法在摘要中建立具有两个生命周期的子类型关系,因为:

  • 有时,为了可替代,新的生命周期必须大于被替换的生命周期。
  • 有时,为了可替代,新的生命周期必须小于被替换的生命周期。

我们可以通过两个简单的例子来检验这一点。


第一个例子可能是最简单的:如果生命周期更大,则可以替换它!

//  Using a lifetime as a bound
struct Reference<'a, T>
    where T: 'a
{
    data: &'a T
}

fn switch<'a, 'b, T>(r: &mut Reference<'a, T>, new: &'b T)
    where 'b: 'a
{
    r.data = new;
}

在这里,编译器只允许替换 if'b至少'a与 life bound 所表示的一样大'b: 'a。这是因为 Rust 厌恶悬空引用,因此容器可能只包含对比它寿命更长的对象的引用。

当用作保证时,较长的生命周期是较短生命周期的子类型,可以代替它。这暗示了@aturon 提到的,在这种用法'static中是所有生命周期的子类型。


第二个例子有点棘手:如果生命周期更短,则可以替换它!

让我们从以下内容开始:

struct Token;

fn restrict<'a, 'b, T>(original: &'a T, _: &'b Token) -> &'b T
    where 'a: 'b
{
    original
}

以下用法是正确的:

fn main() {
    let i = 4;

    {
        let lesser = Token;
        let k = restrict(&i, &lesser);
        println!("{}", k);
    }
}

我们之前的演示说我们可以用更长的寿命代替更短的寿命:

fn main() {
    let greater = Token;
    let j;  // prevent unification of lifetimes

    {
        let i = 4;
        j = restrict(&i, &greater);
    }
    println!("{}", j);
}

error: `i` does not live long enough
j = restrict(&i, &greater);

当用作约束时,较小的生命周期是较大生命周期的子类型,可以代替它。在这种用法中,'static是所有生命周期的超类型。


因此,生命周期之间没有单一的子类型关系,因为它们服务于两个完全相反的目的!

回顾一下:

  • 当用作保证时:greater <: lesser
  • 当用作约束时:lesser <: greater

注意:一些生命周期可以同时充当保证和约束。

于 2016-02-14T17:06:01.800 回答