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

时间:2019-08-27 21:04:41

标签: 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 }
    }
}

函数new1new2之间是否有区别?我假设arg&self会很重要吗?在任何情况下都倾向于采用new2实施还是采用其他方式?

1 个答案:

答案 0 :(得分:1)

这两种方法最终完全相同,但是值得学习为什么。一路上,我们将学习终生胁迫

如果第二个生命周期比第一个生命周期短(或包含在第一个生命周期中),则可以将其强制转换为另一个生命周期。通常用'a: 'b表示,这意味着生存期'a完全包围了生存期'b。常用术语是'a'b寿命更长。这种强制的原因是,如果需要,您总是可以缩短寿命。如果引用在某个生命周期内有效,那么它在较长生命周期中包含的任何较短生命周期中也有效。

因此,考虑到这一点,new1new2可以采用哪种参数?我们有一个固定的生存期'a,因为整个实现在该生存期中都是通用的。但是,new1不仅可以使用&'a u8,而且可以将&'b u8强制为'b的任何'a。也就是说,'b: 'a'b'a长。

new2稍有不同,但最终效果相同。该方法在生命周期'b中是通用的,如果使用&'c u8,则可以采用任何'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 }
    }
}

编译器抱怨。为什么?现在输出必须为Name<'a>,在new2中,我们将返回Name<'b>。除非Name<'a>,否则这对'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 }
    }
}

(playground link)

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