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

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

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

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

#[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; 可以在这里工作,但对我来说似乎是错误的。

【问题讨论】:

    标签: rust lifetime


    【解决方案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)。
    • 这是有道理的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    相关资源
    最近更新 更多