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

Understanding lifetimes: max lifetime and 'static

我对 Rust 生命周期的学习过程是这样的(基于 Rust 书):

  1. 我想注释,当引用后面的值超出范围时
  2. 通常(不总是!参见 .data 部分,即“静态”)值位于 {} 块中
  3. 我们注释像 't: {…} 这样的块,例如结构字段的生命周期类似于 &'t ident,具有相同的生命周期名称 t
  4. 这个理解是错误的。为什么?结构实现者很可能不知道块名称定义,并且同一结构可能有多个块名称定义。
  5. 所以定义't: {…}和用法&'t ident必须完全独立
  6. 编译器可以轻松确定定义,因此用户无需编写 't: {…}。程序员只需要关心&'t ident规范部分。
  7. 编译器可以分析函数体(在 struct 的情况下:使用结构成员)并确定 &'t ident 部分。
  8. 这个理解是错误的。为什么?因为有时候函数体(或者struct成员的使用)还不可用(比如一个trait指定了一个函数,但是实现是由其他人在未来完成的)。
  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);
}

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

这似乎适用于以下人为设计的较短函数:

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

如果我们添加一些 'static return 值,最坏情况下的生命周期是 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: &'a Stats<'static> 可以在这里工作,但我觉得不对。

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

而不是假装 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);
}