ライフタイム

その変数が属してるスコープの事です。Rust では使用期限が過ぎた変数を使えない様に厳しく確認されます。

use std::borrow::Borrow;

fn plus<'a, 'b, T>(a: &'a T, b: &'b T) -> i32
where
  T: Borrow<i32>,
{
  a.borrow() + b.borrow()
}

fn main() {
  {
    // 'a
    let thirty_three: i32 = 33;

    {
      // 'b
      let one: i32 = 1;
      assert_eq!(plus(&thirty_three, &one), 34);
    }
  }
}

main処理の最初のブロックスコープには'a、その中の2つ目のブロックスコープには'bという名前が付いているとします。ここで変数thirty_threeのライフタイムは'aoneのライフタイムは'bまはた'aと考える事ができます。

Rust の関数ではジェネリック型を置く場所にライフタイムも置くことができます。関数plunでは'aに属するTの参照と、'bに属するTの参照を引数に期待するということになります。また上記の説明の通りライフタイムは'aだけでも動きます。

fn plus<'a, T>(a: &'a T, b: &'a T) -> i32
where
  T: Borrow<i32>,
{
  a.borrow() + b.borrow()
}

実はライフタイムが1つしかなかったり、引数の値ぞれぞれが別のライフタイムを持つのでいい場合ライフライムは省略できます。

fn plus<T>(a: &T, b: &T) -> i32
where
  T: Borrow<i32>,
{
  a.borrow() + b.borrow()
}

これはfn plus<'a, 'b, T>(a: &'a T, b: &'b T) -> i32と展開されます。

先程'bで定義した変数は'b'aどちらにも属すると考えれると書きましたが、ライフタイムは'bで定義した変数の参照を'aなライフタイムの変数に入れることはできません。以下はエラーになります。

{
  // 'a
  let a = Foo { value: 33 };
  let b;

  {
    // 'b
    let c = Foo { value: 1 };

    b = &c;
    // error: `c` does not live long enough
  }
}

これは'bを抜けた後にbが終わった変数cの参照を持つことになってしまう為です。関数ではさらに子ブロックスコープに囲まれて生存期間がハッキリする為エラーにはなりません。