在结构实现中使用不同的生命周期

raj*_*raj 5 rust

我试图更好地了解Rust的寿命。

struct Name<'a> {
    arg: &'a u8,
}
impl<'a> Name<'a> {
    fn new1(arg: &'a u8) -> Name<'a> {
        Name { arg }
    }
    fn new2<'b>(arg: &'b u8) -> Name<'b> {
        Name { arg }
    }
}
Run Code Online (Sandbox Code Playgroud)

是否有功能之间的差异new1new2?我假设,如果会的问题arg&self?在任何情况下都new2倾向于实现吗?

SCa*_*lla 2

这两种方法最终完全相同,但值得了解其原因。一路上,我们将了解终身强制

如果第二个生命周期比第一个生命周期短(或者更确切地说,包含在第一个生命周期中),则一个生命周期可以强制进入另一个生命周期。这通常被标记'a: 'b为意味着生命周期'a完全包含生命周期'b。通常的术语是'a“超越” 'b。这种强制的原因是,如果需要的话,你总是可以缩短寿命。如果引用在某个生命周期内有效,那么它在较长生命周期中包含的任何较短生命周期内也有效。

那么考虑到这一点,可以采取什么样的论据new1new2?我们有一个固定的生命周期'a,因为整个实现在该生命周期中是通用的。但是,new1不仅可以拿&'a u8,而且任何&'b u8如果都'b可以胁迫'a。即'b: 'a'b比 长'a

new2略有不同,但最终效果相同。该方法在生命周期内是通用的'b,可以采用任何&'c u8if 'c: 'bnew2在技​​术上仍然是通用的'a,但由于它根本不使用'a,因此可以忽略。也就是说,忽略通用参数会令人困惑(为什么要使用该参数?),因此最好使用它new1

new1更喜欢它的另一个原因new2是它更适合Self. 如果我们尝试将输出更改为Self

impl<'a> Name<'a> {
    fn new1(arg: &'a u8) -> Self {
        Name { arg }
    }
    fn new2<'b>(arg: &'b u8) -> Self {
        Name { arg }
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器抱怨。为什么?现在输出必须是Name<'a>且在 中new2,我们将返回Name<'b>。这不能强制执行Name<'a>except 'b: 'a,因此我们必须将其添加为'b:

impl<'a> Name<'a> {
    fn new1(arg: &'a u8) -> Self {
        Name { arg }
    }
    fn new2<'b: 'a>(arg: &'b u8) -> Self {
        Name { arg }
    }
}
Run Code Online (Sandbox Code Playgroud)

(游乐场链接)

在这种情况下,很明显这new1是优越的,因为它甚至不需要第二个生命周期,但仍然允许完全相同的输入。