関数とライフタイム

参照にはライフタイムがあり、これは参照する値よりも「長く存続」してはなりません。これは借用チェッカーによって検証されます。

これまで見てきたとおり、ライフタイムは暗黙に扱えますが、&'a Point&'document str のように明示的に指定することもできます。ライフタイムは ' で始まり、'a が一般的なデフォルト名です。&'a Point は、「少なくともライフタイム a の間は有効な、借用した Point」とと解釈します。

ライフタイムは常にコンパイラによって推測されます。自分でライフタイムを割り当てることはできません。明示的なライフタイム アノテーションを使用すると、あいまいなところに制約を課すことができます。それに対し、コンパイラはその制約を満たすライフタイムを設定できることを検証します。

関数に値を渡し、関数から値を返すことを考慮する場合、ライフタイムはより複雑になります。

#[derive(Debug)]
struct Point(i32, i32);

fn left_most(p1: &Point, p2: &Point) -> &Point {
    if p1.0 < p2.0 {
        p1
    } else {
        p2
    }
}

fn main() {
    let p1: Point = Point(10, 10);
    let p2: Point = Point(20, 20);
    let p3 = left_most(&p1, &p2); // p3 のライフタイムは?
    println!("p3: {p3:?}");
}
This slide should take about 10 minutes.

この例では、コンパイラは p3 のライフライムを推測するこが出来ませんん。関数本体の内部を見ると、p3 のライフタイムは p1p2 のいずれか短いしかし想定できることがわかります。ただし、型と同様に、Rust では関数の引数や戻り値にライフタイムの明示的なアノテーションが必要です。

left_most'a を適切に追加します。

fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {

これは、「p1 と p2 の両方が 'a より長く存続すると、戻り値は少なくとも 'a の間存続する」という意味になります。

一般的なケースでは、次のスライドで説明するようにライフタイムを省略できます。