昨天IRC里对此有一些讨论,让我感到隐隐约约的不满。
问题是:
如何在结构上定义生命周期以将其内容限制为
只有与“自身”一样长寿的事物。
i.e. a 'self
那类的东西。
我最初的反应是:你不能。
如果你创建一个结构体Foo<'a>
,与其关联的生命周期是从它包含的引用推断出来的;除非该结构包含对itself(不可能),你不能有这样的'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
has 'one
-
&b
has 'two
-
'static
> 'one
> 'two
(那是,'two
的边界是'one
).
-
foo1
has 'one
-
foo2
has 'two
现在,我的困惑是:
Foo<'a>
表明'a
is the 最小寿命界限可以包含在以下实例中Foo
.
Since 'one
> 'two
, foo2
应该能够包含一个&'one a
;这有效。
Since 'two
> 'one
, foo1
should not能够容纳&'two b
;然而,这有效。
Why?
看来我的困惑是由两个误解之一造成的:任何一个:
-
的实例foo1
事实上是Foo<'two>
, not Foo<'one>
.
我不明白为什么会出现这种情况,因为它是在factory<'a>
where <'a>
是的生命周期c
;这是'one
, not 'two
。绝对没有办法c
can be &'two
在上面的例子中。一生'two
在函数工厂中不可用Foo
被建造。
2)结构生命周期并不像我理解的那样工作;即一生'a
on a Foo
实例在创建实例之后可以以某种方式改变(例如在移动时?)
……但我不知道是哪一个。
参考的生命周期参数是协变:它们可以替换为shorter必要时终身。
基本上,你的做法是错误的。当你有一个&'one Bar
,您不能将引用分配给带有shorter生命周期(例如'two
此处),否则当执行离开时,引用将悬空'two
范围。然而,当你有一个&'two Bar
,您可以将引用分配给具有较长生命周期的值(例如'one
and 'static
),因为引用将在引用对象之前超出范围。
为什么你的程序可以编译?编译器不仅使用来自调用的信息factory
选择适当的寿命;它还使用作业中的信息 https://doc.rust-lang.org/stable/rust-by-example/types/inference.html. &a
有类型&'one Bar
and &b
有类型&'two Bar
。因为'two
之后开始'one
并在之前结束'one
,编译器可以coerce a &'one Bar
to a &'two Bar
。用面向对象的术语来说,&'one Bar
is a &'two Bar
(&'one Bar
是一个子类型&'two Bar
)。就像在 Java 中一样,你可以传递一个String
作为期望的函数的参数Object
。 Java 中类的子类型关系是子类是其父类的子类型,但生命周期的子类型关系是较长生命周期是较短生命周期的子类型。
这意味着我们找到了一个通用类型&a
and &b
: &'two Bar
。因此,编译器推断'two
for 'a
在致电factory
.
请注意,类型foo2
分配时不会改变;值的类型始终是静态的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)