【Rust】ライフタイム
Rustにはライフタイムという概念があります。
それはリソースの安全な管理を実現するために存在しているのですが、
これが意外とややこしいのものです。
ドキュメントにもまとめらていますが、
ここで噛み砕いて簡単にまとめたいと思います。
ライフタイムがしてくれること
Aというリソースがあり、それに対する参照をBが持つとします。
これでBはAの値にアクセスすることができます。
しばらくしてAが役目を終え解放されたあとにBがAを使用するようなことがあった場合、
BはNULLを参照することになってしまいます。
これはプログラムがクラッシュする原因になります。
ライフタイムはこのような現象を防ぐための役割を担っています。
ライフタイムの宣言
簡単な例を見ていきましょう。
1 2 3 4 5 6 7 8 9 10 11 |
fn func<'a>(y: &'a mut i32) { *y = *y*10 } fn main() { let mut x = 10; func(&mut x); println!("{}", x); } |
func関数はi32型の参照を受け取ります。
関数内で10倍したあと処理を終えます。
先に挙げた例で言うと、
main関数内で宣言されたxがAにあたり、
func関数の引数であるy: &mut i32がBとなります。
‘aという記述があります。(aの部分は任意の文字)
これがライフタイムの宣言です。
この宣言によってBはAよりも長く存在しないということを示します。
これのおかげでfunc関数内でyを使用している間はxの値に対してアクセスできるということが保証されます。
ちなみにサンプルのfunc関数はこのような書き方もできます。
1 2 3 4 |
fn func(y: &mut i32) { *y = *y*10 } |
‘aの宣言を省略することができます。
しかし構造体を使う場合は明示的に宣言する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 |
struct Hoge { x: &i32 } fn main() { let a = 10; let h = Hoge{x:&a}; println!("{}", h.x); } |
これだとコンパイルできません。
1 2 3 4 5 6 7 |
$ rustc lt.rs -o lt error[E0106]: missing lifetime specifier --> lt.rs:2:6 | 2 | x: &i32 | ^ expected lifetime parameter |
ライフタイムを宣言しましょう。
1 2 3 |
struct Hoge<'a> { x: &'a i32 } |
ちなみに参照が複数ある場合、その数だけライフタイムを宣言する必要があります。
1 2 3 4 |
struct Hoge<'a, 'b> { x: &'a i32, y: &'b i32 } |
ピンとこない場合
error[E0106]: missing lifetime specifierのメッセージとともに、
ライフタイムを宣言するべき場所をコンパイラが指定しくれますので、
それに従っておきましょう。
僕はそうしています。
いずれ理解できる気がします。