为什么你会在结构中使用相同的生命周期?

时间:2017-06-22 21:26:16

标签: struct rust lifetime

这个问题类似于When is it useful to define multiple lifetimes in a struct?,但希望有足够的不同。这个问题的答案很有帮助,但侧重于一种方法的优点(对结构中的引用使用不同的生命周期),而不是缺点(如果有的话)。像这样的问题,正在寻找关于如何在创建结构时选择生命周期的指导。

将其称为捆绑在一起的版本,因为 x y 需要具有相同的生命周期:

struct Foo<'a> {
    x: &'a i32,
    y: &'a i32,
}

并将其命名为 loose 版本,因为生命周期可能会有所不同:

struct Foo<'a, 'b> {
    x: &'a i32,
    y: &'b i32,
}

引用问题的答案给出了一个明确的案例,其中客户端代码可以在松散版本的情况下编译/运行,但捆绑在一起的版本将失败。不是这样的情况,任何适用于绑定版本的客户端代码也适用于松散版本,并且将保证同样安全(即安全)?正面不是真的。从结构设计者的角度来看, loose 版本显然更加灵活。鉴于它是一个好的/可接受的答案,指导可能是 - 当在结构中使用引用时总是给它们不同的生命周期。

这个建议的缺点是什么,忽略了额外的打字?例如,要求结构中的引用具有相同的生命周期是否有益?

1 个答案:

答案 0 :(得分:6)

  

要求结构中的引用具有相同的生命周期

是否有益处

是的,它不仅仅是一个结构。如果生命周期总是彼此不同,那么你就无法写出这个函数:

fn foo<'a, 'b>(a: &'a str, b: &'b str) -> &str {
    // What lifetime to return?
    if (global_random_number() == 42) {
        a
    } else {
        b
    }
}

应用于struct,你可以这样:

struct EvenOrOdd<'a, 'b> {
    even: &'a str,
    odd: &'b str,
}

impl<'a, 'b> EvenOrOdd<'a, 'b> {
    fn do_it(&self, i: u8) -> &str {
        if i % 2 == 0 {
            self.even
        } else {
            self.odd
        }
    }
}

请注意,虽然这会编译,但它不会返回一个可以比结构本身更长的字符串,这不是预期的。此代码失败,即使它应该能够工作:

fn foo<'a, 'b>(a: &'a str, b: &'b str) {
    let result = { EvenOrOdd { even: a, odd: b }.do_it(42) };

    println!("{}", result);
}

这将适用于统一的生命周期:

struct EvenOrOdd<'a> {
    even: &'a str,
    odd: &'a str,
}

impl<'a> EvenOrOdd<'a> {
    fn do_it(&self, i: u8) -> &'a str {
        if i % 2 == 0 {
            self.even
        } else {
            self.odd
        }
    }
}

这与链接答案相反,后者有评论:

  

您希望能够使用聚合值并在使用后拆分部分

在这种情况下,我们希望采用聚合值并统一

在极少数情况下,您可能需要在不同的统一生命周期之间穿针:

struct EvenOrOdd<'a, 'b: 'a> {
    even: &'a str,
    odd: &'b str,
}

impl<'a, 'b> EvenOrOdd<'a, 'b> {
    fn do_it(&self, i: u8) -> &'a str {
        if i % 2 == 0 {
            self.even
        } else {
            self.odd
        }
    }
}

虽然这在需要的时候很有用,但我无法想象如果我们每次都必须这样写的话,会发出嚎叫和咬牙切齿的声音。

  

忽略额外输入

我不会。

foo<'a>(Bar<'a>)

肯定比

foo<'a, 'b', 'c, 'd>(Bar<'a, 'b', 'c, 'd>)

如果您没有从额外的通用参数中受益。