了解生命周期:最大生命周期和“静态”

Posted

技术标签:

【中文标题】了解生命周期:最大生命周期和“静态”【英文标题】:Understanding lifetimes: max lifetime and 'static 【发布时间】:2021-01-03 01:22:57 【问题描述】:

我对 rust 生命周期的学习过程如下所示(基于 rust 书):

    我想在引用后面的值超出范围时进行注释 通常(并非总是如此!请参阅 .data 部分,即“静态”)值位于 块中 我们注释块像 't: … 和例如struct 字段的生命周期类似于 &'t ident 具有相同的生命周期名称 t 这种理解是错误的。为什么?结构实现者很可能不知道块名称定义,并且同一结构可能有多个块名称定义。 所以't: …的定义和&'t ident的用法必须完全独立。 编译器可以轻松确定定义,因此用户无需编写't: …程序员只需要关心&'t ident 规范部分。 编译器可以分析函数体(在 struct 的情况下:使用结构成员)并确定 &'t ident 部分。 这种理解是错误的。为什么?因为有时函数体(或结构成员的使用)尚不可用(例如,特征指定了一个函数,但未来由其他方完成)。 因此,structfn 必须分别在其结构定义或函数签名中完全指定生命周期。 规范大多遵循相同的启发式规则。所以我们引入了生命周期省略。它根据针对最常见用例的规则插入生命周期,我们可以随时选择退出。

在这一点上,我认为我的理解非常接近它的实际工作方式。但是现在,我的理解错了。让我们看一个例子:

#[derive(Debug)]
struct Stats 
  league: &str,


const NAME: &str = "rust";

fn more_difficult_league(s1: &Stats, s2: &Stats) -> &str 
  if s1.league == s2.league 
    s1.league
   else if s1.league == "php" 
    s2.league
   else 
    "C++"
  



fn main() 
  let mut st = Stats  league: name ;
  let dleague = more_difficult_league(&st, &st);
  println!("", dleague);

显然,我省略了任何生命周期规范。

结构字段的生命周期是程序的整个持续时间 ('static) 或与结构一样长的时间 (Stats<'a>league: &'a str)

在函数/方法中,我们可能会得到生命周期为'a'b'c、...的引用。返回值的生命周期是多少?

要么是某个静态值 ('static) 要么总是相同的特定生命周期(如'c) 要么是一个特定的生命周期,要么在编译或运行时就知道。对于编译器,我们必须指定最坏情况下的生命周期max('a, 'b, 'c, …)。据我所知,这可以通过为每个引用赋予相同的生命周期来实现。

这似乎适用于以下人为的、较短的功能:

fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'a str 
  if s1.league == s2.league 
    s1.league
   else 
    s2.league
  

如果我们添加一些'static返回值,最坏情况下的生命周期是max('a, 'static),大概是'static

fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'static str 
  if s1.league == s2.league 
    s1.league
   else if s1.league == "PHP" 
    s2.league
   else 
    "C++"
  

这为s2.league 提供error[E0621]: explicit lifetime required in the type of s1lifetime 'static required

我的理解在哪一点上是错误的?提前感谢您对我的包容。

免责声明: help: add explicit lifetime 'static to the type of s1: &amp;'a Stats&lt;'static&gt; 可以在这里工作,但对我来说似乎是错误的。

【问题讨论】:

【参考方案1】:

我会按照下面提供的方式更改您的代码。

而不是假装more_difficult_league()的结果 有一个静态生命周期(当我们提到 s1 时,情况并非如此 或s2,编译器会抱怨),我们可以引入 此结果的新生命周期注释并指定 参数的生命周期必须超过这个结果( where 子句)。

#[derive(Debug)]
struct Stats<'a> 
    league: &'a str,


const NAME: &str = "rust";

fn more_difficult_league<'a, 'b, 'c>(
    s1: &'a Stats,
    s2: &'b Stats,
) -> &'c str
where
    'a: 'c,
    'b: 'c,

    if s1.league == s2.league 
        s1.league
     else if s1.league == "PHP" 
        s2.league
     else 
        "C++"
    


fn main() 
    let st = Stats  league: NAME ;
    let dleague = more_difficult_league(&st, &st);
    println!("", dleague);

【讨论】:

附加问题:您认为我的陈述“据我所知,这可以通过给每个引用相同的生命周期来完成”是正确的吗? @meisterluk 我想是的,只要您在函数代码中不与此相矛盾(例如返回静态 str)。 这是有道理的。谢谢!

以上是关于了解生命周期:最大生命周期和“静态”的主要内容,如果未能解决你的问题,请参考以下文章

c++类中 各种成员的生命周期?

C里面静态动态,生命周期.作用域怎么区分?怎么用

java 静态变量生命周期(类生命周期)

如何为具有生命周期'a的结构实现具有'静态生命周期的特征?

java 静态变量生命周期(类生命周期)(转)

C语言中,哪种存储类的作用域与生命周期是不一致的?