gpt4 book ai didi

rust - 在 Rust 中与生命周期的子类型关系作斗争

转载 作者:行者123 更新时间:2023-11-29 07:40:37 25 4
gpt4 key购买 nike

我浏览了marker section,感觉很蠢关于 subtyping 的 Rust 文档和维基百科文章和 variance多次都没有提高我对生命周期子类型关系的理解。

我想我只是习惯了“典型的 OOP 风格”子类关系,比如“Cat <: Animal”意思是“Cat 是 Animal 的一个子类型”,其中“S 是 T 的一个子类型”意思是“任何术语 S可以安全地用于预期类型为 T 的术语的上下文中”。到目前为止一切顺利。

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

(#1) 'a <: 'b <=> lifetime a is no longer than lifetime b.

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

(#2) 'a <: 'b <=> lifetime a can be safely used in a context where lifetime b is expected.

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

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

Edit2:ContravariantLifetime 和 CovariantLifetime 标记已被删除。我们现在有 PhantomData 作为 marker 中的替代品模块。

最佳答案

免责声明:我不完全是 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是所有生命周期的父类(super class)型。


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

概括一下:

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

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

关于rust - 在 Rust 中与生命周期的子类型关系作斗争,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25407632/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com