苦苦挣扎于Rust的生命周期的子类型关系

时间:2014-08-20 14:40:23

标签: rust lifetime subtyping

我感到愚蠢的是,浏览了marker section Rust文档和维基百科关于subtypingvariance多次的文章而没有提高我对生命周期子类型关系的理解。

我认为我只是习惯于“典型的OOP风格”子类关系,例如“Cat&lt ;: Animal”,意思是“Cat是动物的子类型”,其中“S是T的子类型”意味着“任何术语” S可以安全地用于期望类型为T的术语“。到目前为止一切都很好。

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

  

(#1)'a<:'b< =>寿命a不等于寿命b。

你可能会想“当然这意味着什么!”可能是因为<:看起来类似于小于运算符,或者可能是因为“sub”让你想到子集,更短的寿命肯定是更长寿命的一个子集。但是'如果'a'不是'b',那么'b'真的是一个子类型让我们尝试应用维基百科对子类型关系的定义:

  

(#2)'a<:'b< =>生命周期a可以安全地用于预期寿命为b的环境中。

我遇到的问题是我无法调和此问题。你是如何从#2到#1的?因为对我而言,这似乎是一个矛盾...如果你期望某事至少是活着的b并且你有一个比b短的东西,你显然不能在那些有生命周期的东西中使用它是必需的,可以吗?它只是我还是我们得到了生命周期的子类型关系错误?

编辑:(*)根据#rust IRC频道中的Ms2ger,情况就是如此。它也适用于Items迭代器中使用的逆变寿命标记的文档。

Edit2:已删除ContravariantLifetime和CovariantLifetime标记。我们现在PhantomData模块中有{{1}}作为替代。

1 个答案:

答案 0 :(得分:2)

免责声明:我不是一个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;
}

这里,编译器只允许替换,如果'b至少与'a一样长,它由生命周期绑定'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

注意:有些生命周期可以同时作为保证和约束。