为啥不能在结构定义中省略生命周期?

Posted

技术标签:

【中文标题】为啥不能在结构定义中省略生命周期?【英文标题】:Why can the lifetimes not be elided in a struct definition?为什么不能在结构定义中省略生命周期? 【发布时间】:2015-03-03 08:28:50 【问题描述】:
struct Point 
    x: u32,
    y: u32,


struct Line<'a> 
    start: &'a Point,
    end: &'a Point,

这里,startend 字段的唯一可能选项是具有与包含它们的 Line 变量相同或更长的生命周期。我什至无法想象如何使用生命周期说明符来说明字段的生命周期较短。

为什么我必须在这里明确指定生命周期?在这种情况下是否不可能进行省略,如果可以,为什么不呢?

【问题讨论】:

虽然我认为 Rust 可以选择省略结构定义中的生命周期,但它现在不会这样做。您只会看到用于函数/方法的术语 lifetime elision 【参考方案1】:

当你定义一个结构时,你并没有在结构的生命周期和字段的生命周期之间建立关系。正如您所指出的,字段中的引用必须比结构寿命更长。

相反,您正在做的是提供一个“通用生命周期”,在您创建结构时将专门用于该生命周期。这类似于具有类型参数的结构:

struct Foo<T>
    foo: T,

当您构造结构时,编译器会插入适当的生命周期(或类型),然后它会检查一切是否仍然正常。

另一件事是您可以指定相对于彼此的生命周期

struct Line<'a, 'b: 'a> 
    start: &'a Point,
    end: &'b Point,

这表示startend 可以有不同的生命周期,只要end 的生命周期超过start 的生命周期。

为什么编译器不对结构进行生命周期省略?这样做似乎符合 Rust 的精神

(强调我的)

我实际上相信 Rust 倾向于显式性,尤其是在定义***项目(如函数、结构)时。

函数的生命周期省略规则的范围非常小,empirically found in RFC 141 的成功率很高 (87%)。这是一个非常符合人体工程学的投资回报。

也许在某些时候,结构会出现类似的省略,但这还不是一个足够大的问题。如果您对此有强烈的感觉,那么我强烈建议您在 user forum 上寻求共识,进入开发者论坛,然后最终制定 RFC。

RFC 2093 增加了少量的推理。在实现之前,您必须表示作为引用的泛型类型需要比引用长:

struct Foo<'a, T: 'a> 
    start: &'a T,

没有任何情况想要这个绑定,所以在 RFC 实施之后,你可以说:

struct Foo<'a, T> 
    start: &'a T,

【讨论】:

从这个答案中不清楚为什么声明结构时生命周期是必要的 您收到我在您的问题中添加的评论了吗?如果我理解你,那么答案是“因为编译器需要它”。如果您的结构中有引用,则必须指定这些引用的生命周期。结构声明没有生命周期省略,尽管我认为编译器可以自动为每个生命周期放置 'a。为此,您必须向 Rust 本身提出功能请求。 @RajV,因为没有它们就没有明显的方法。结构中的非静态引用必然意味着应该至少有一个生命周期参数,但可以有更多,这意味着另一回事。 @Shepmaster,“结构声明没有生命周期省略,尽管我认为编译器可以自动为每个生命周期添加 'a'”。问题正是:为什么编译器不对结构进行生命周期省略?这样做似乎符合 Rust 的精神,在我看来,这样做是有充分理由的。我认为你的答案根本没有解决这个问题,它只提供了明确的生命周期声明的例子,所以我很惊讶它被接受了。 @AxiomaticNexus 我个人会坚持一生,直到某些事情迫使我使用多个。如果我正在编写一个在发布后我会犹豫更改的公共 API,这可能会改变。【参考方案2】:

假设我们有一个Line 的构造函数:

impl<'a> Line<'a> 
    fn new(start: &'a Point, end: &'a Point) -> Line<'a>  // '
        Line 
            start: start,
            end: end,
        
    

new 返回一个Line&lt;'a&gt;。为了能够参数化具有生命周期的类型(就像我们在此处使用 Line&lt;'a&gt; 所做的那样),该类型必须定义生命周期参数!尽管编译器可以在必要时自动定义生命周期参数,但只要查看源代码中的定义,就更容易确定类型是否具有生命周期参数。

结构和枚举的生命周期参数在借用检查器中起着重要作用。它们让编译器知道结构保留借用某些值。然后,当您尝试更改具有活动借用的值时,编译器会返回错误。

fn main() 
    let mut start = Point  x: 2, y: 4 ;
    let end = Point  x: 7, y: 10 ;
    let line = Line::new(&start, &end);
    start.x = 3; // error: cannot assign to `start.x` because it is borrowed

【讨论】:

以上是关于为啥不能在结构定义中省略生命周期?的主要内容,如果未能解决你的问题,请参考以下文章

为啥作为参数传递的特征对象的生命周期需要更高等级的特征边界,而结构不需要?

为啥 Rust 编译器要求我限制泛型类型参数的生命周期(错误 E0309)?

为啥在以下示例中明确声明了生命周期? [复制]

React Native组件的结构和生命周期

Maven生命周期

为啥我们使用 - ngAfterContentInit 生命周期方法