【Rust】ライフタイムは賞味期限

2024/06/16に公開

はじめに

Rustのライフタイムと明示的アノテーションについて書きます。
Rustで関数を書いたときにコンパイラに怒られたので、その内容についての投稿です。

ライフタイムとは?

バナナに賞味期限があるように、変数がどのくらいの間メモリに存在するのかを示したもの。
Rustでは変数がいつまで生き残っているのかをはっきりさせるために、ライフタイムという仕組みを使っています。
これにより、安全にメモリを管理しています。

ライフタイムの具体的な例については、以下の記事が参考になります。
https://doc.rust-jp.rs/rust-by-example-ja/scope/lifetime.html

コンパイラに怒られたコード

新鮮なバナナを選ぶシンプルなコードです。

pub fn lifetime() {
    let taiwan_banana = String::from("台湾🍌Fresh Banana");
    let philippine_banana = String::from("フィリピン🍌Green Banana");

    let result = choose_fresh_banana(&taiwan_banana, &philippine_banana);

    println!("新鮮なバナナは {}", result);
}

fn choose_fresh_banana(x: &str, y: &str) -> &str {
    if x.contains("Fresh") {
        x
    } else {
        y
    }
}

一見問題ないように見えますが、よく見ると choose_fresh_bananaでエラーが出ています。

エラー内容はこちら。

missing lifetime specifier
this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from x or y

Rustのコンパイラは、多くの場合はライフタイムの推測ができますが、引数と戻り値のライフタイムの関係を正確に判断することができません。
そのため、関数の引数と戻り値の関係については明示的に指定する必要があります。

https://doc.rust-jp.rs/rust-by-example-ja/scope/lifetime/explicit.html

ライフタイムを明示的に示すために 'a をつけます。

- fn choose_fresh_banana(x: &str, y: &str) -> &str {
+ fn choose_fresh_banana<'a>(x: &'a str, y: &'a str) -> &'a str {

これでエラーが解決できます。

修正したコードは以下になります。

pub fn lifetime() {
    let taiwan_banana = String::from("台湾🍌Fresh Banana");
    let philippine_banana = String::from("フィリピン🍌Green Banana");

    let result = choose_fresh_banana(&taiwan_banana, &philippine_banana);

    println!("新鮮なバナナは {}", result);
}

fn choose_fresh_banana<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.contains("Fresh") {
        x
    } else {
        y
    }
}

無事、🍌が表示されました。

コラボスタイル Developers

Discussion