Rustの構造体は、構造体の定義に明示的なライフタイム(lifetimes)を指定することで他のオブジェクトへの参照を保持できます。これは、コンパイラーがいかなる参照も無効にならないことを確認できるようにするために必要です。以下は例です:
struct Book<'a> { title: &'a str, author: &'a str, }
ここでは、Book構造体に同じライフタイム'aを持つ2つの参照が含まれています。このような構造体を返す関数を書く場合、関数の内部ロジックに関係なく、すべての参照が有効であることを保証する必要があります:
fn book_factory<'a>(title: &'a str, author: &'a str) -> Book<'a> { Book { title, author } }
もし関数から返される構造体が、フィールドである参照がこの関数のローカル変数を指している場合、コンパイルエラーが発生します。なぜなら、参照のライフタイムが安全なアクセスのために不十分だからです。
あるフィールドに参照(&str)を持ち、別のフィールドにStringを持つ構造体を作成できますか?なぜこれが問題になる可能性があるのですか?
よくある誤った答え:「はい、できます。安全です。」
実際には、&strがStringから取得された場合、構造体がそのStringを超えて生存することになると、参照はダングリング(dangling reference)になります。たとえば:
struct Test<'a> { s1: &'a str, s2: String, } fn main() { let s = String::from("hello"); let t = Test { s1: &s, s2: s }; // t.s1は、実際にはs2(s)が生存している間は安全ですが、s2が最初に削除されるとエラーになります }
物語 あるプロジェクトでは、一時的な文字列への参照を含む構造体を返す再帰関数からの戻り値を試みましたが、コードはコンパイルできず、ローカル変数のライフタイムを取り除くためにはかなりの書き直しが必要でした。
物語 開発者は関数で作成された配列要素への参照を持つ構造体を使用するつもりでしたが、返された後、その参照は無効になり、コンパイラーがこれを防ぎました。
物語 企業プロジェクトでは、開発者がコレクションから削除された別のオブジェクトの文字列への参照を保持していましたが、その参照は無効になり、後でその参照にアクセスしようとしたときにpanicが発生しました。