← トップページに戻る

Rustの勉強[ライフタイム その4]

ぎじゅつ
Rust

はじめに

NO IMAGEThe Rust Programming Language 日本語版 - The Rust Programming Language 日本語版
を読んでいる
色々やってて後回しになっていて自分にムカついた
こういうのが一番自分に腹立つので継続の優先順位は上げとこう

今日読む場所

NO IMAGEライフタイムで参照を検証する - The Rust Programming Language 日本語版
これ

お勉強

メモ

ここまで、所有された型を保持する構造体だけを定義してきました。構造体に参照を保持させることもできますが、 その場合、構造体定義の全参照にライフタイム注釈を付け加える必要があるでしょう。

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    // 僕をイシュマエルとお呼び。何年か前・・・
    let novel = String::from("Call me Ishmael. Some years ago...");
    //                                                  "'.'が見つかりませんでした"
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
}
struct User<'a> {
    name_a: String,    // 所有権(ライフタイムに縛られない)
    name_b: &'a str,   // 借用('a の間だけ有効)
    name_c: &'a str,   // 借用('a の間だけ有効)
}
struct Profile<'a, 'b> {
    short_bio: &'a str, // 短い寿命でもOK
    long_bio: &'b str,  // 長い寿命が必要
}

NO IMAGEライフタイムで参照を検証する - The Rust Programming Language 日本語版

fn first_word<'a>(s: &'a str) -> &'a str {

多くのRustコードを書いた後、Rustチームは、Rustプログラマが、 特定の場面で何度も同じライフタイム注釈を入力していることを発見しました。これらの場面は予測可能で、 いくつかの決まりきったパターンに従っていました。開発者はこのパターンをコンパイラのコードに落とし込んだので、 このような場面には借用チェッカーがライフタイムを推論できるようになり、明示的な注釈を必要としなくなったのです。

ここで、このRustの歴史話が関係しているのは、他にも決まりきったパターンが出現し、コンパイラに追加されることもあり得るからです。 将来的に、さらに少数のライフタイム注釈しか必要にならない可能性もあります。

最初の規則は、参照である各引数は、独自のライフタイム引数を得るというものです。換言すれば、 1引数の関数は、1つのライフタイム引数を得るということです: fn foo<'a>(x: &'a i32); 2つ引数のある関数は、2つの個別のライフタイム引数を得ます: fn foo<'a, 'b>(x: &'a i32, y: &'b i32); 以下同様。

2番目の規則は、1つだけ入力ライフタイム引数があるなら、そのライフタイムが全ての出力ライフタイム引数に代入されるというものです: fn foo<'a>(x: &'a i32) -> &'a i32。

3番目の規則は、複数の入力ライフタイム引数があるけれども、メソッドなのでそのうちの一つが&selfや&mut selfだったら、 selfのライフタイムが全出力ライフタイム引数に代入されるというものです。 この3番目の規則により、必要なシンボルの数が減るので、メソッドが遥かに読み書きしやすくなります。

シグニチャは、参照に紐づけられるライフタイムがない状態から始まります:

fn first_word(s: &str) -> &str {

そうして、コンパイラは最初の規則を適用し、各引数が独自のライフタイムを得ると指定します。 それを通常通り'aと呼ぶので、シグニチャはこうなります:

fn first_word<'a>(s: &'a str) -> &str {

1つだけ入力ライフタイムがあるので、2番目の規則を適用します。2番目の規則は、1つの入力引数のライフタイムが、 出力引数に代入されると指定するので、シグニチャはこうなります:

fn first_word<'a>(s: &'a str) -> &'a str {

もうこの関数シグニチャの全ての参照にライフタイムが付いたので、コンパイラは、 プログラマにこの関数シグニチャのライフタイムを注釈してもらう必要なく、解析を続行できます。

別の例に目を向けましょう。今回は、リスト10-21で取り掛かったときにはライフタイム引数がなかったlongest関数です:

fn longest(x: &str, y: &str) -> &str {

最初の規則を適用しましょう: 各引数が独自のライフタイムを得るのです。今回は、 1つではなく2つ引数があるので、ライフタイムも2つです:

fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {

2つ以上入力ライフタイムがあるので、2番目の規則は適用されないとわかります。また3番目の規則も適用されません。 longestはメソッドではなく関数なので、どの引数もselfではないのです。3つの規則全部を適用した後でも、 まだ戻り値型のライフタイムが判明していません。このために、リスト10-21でこのコードをコンパイルしようとしてエラーになったのです: コンパイラは、ライフタイム省略規則全てを適用したけれども、シグニチャの参照全部のライフタイムを計算できなかったのです。

まとめ

NO IMAGEライフタイムで参照を検証する - The Rust Programming Language 日本語版