静的ライフタイム
Rustはいくつかの定義済みのライフタイムを持ちます。その中の一つが
'staticです。このような2つの状況に出会うかもしれません。
// 'staticライフタイムで参照する let s: &'static str = "hello world"; // トレイト境界としての'static fn generic<T>(x: T) where T: 'static {}
両者は関係していますが、微妙に異なります。Rustを学ぶ際に混同してしまうもの の一つです。それぞれについて例を見ていきましょう。
参照のライフタイム
参照のライフタイムとしての'staticは、プログラムが走っている間中有効なデータ
への参照を表します。これを短いライフタイムに圧縮することもできます。
'staticライフタイムの変数を作る方法は2つありますが、両方とも
バイナリの読み取り専用メモリに保存されます。
static宣言で定数を作る。&'static str型の文字列リテラルを作る。
以下の例はそれぞれの方法を示しています。
// `'static`ライフタイムの定数を作る。 static NUM: i32 = 18; // `NUM`の参照を`'static`ライフタイムを入力のライフタイムに圧縮して // 返す。 fn coerce_static<'a>(_: &'a i32) -> &'a i32 { &NUM } fn main() { { // `string`リテラルを作ってプリントする。 let static_string = "I'm in read-only memory"; println!("static_string: {}", static_string); // `static_string`がスコープを出た時、参照は使えなくなりますが、 // データはバイナリに残ります。 } { // `coerce_static`に使う整数を作る。 let lifetime_num = 9; // `NUM`を`lifetime_num`のライフタイムに圧縮する let coerced_static = coerce_static(&lifetime_num); println!("coerced_static: {}", coerced_static); } println!("NUM: {} stays accessible!", NUM); // NUM: {}はまだアクセスできます。 }
トレイトの境界
トレイトの境界として使った時、静的でない参照を含むことができないことを 意味します。つまり、受け取り手はその型の変数を好きなだけ保持することができ、 dropするまで無効にならないということです。
所有しているすべてのデータは'staicライフタイム境界を持ちますが、その参照は
持ちません。
use std::fmt::Debug; fn print_it( input: impl Debug + 'static ) { println!( "'static value passed in is: {:?}", input ); } fn use_it() { // iは所有していて、参照を持たないので'staticです。 let i = 5; print_it(i); // &iはuse_it()で定義されたスコープでしか使えないので、 // 'staticではありません。 print_it(&i); }
コンパイラはこのように出力します。
error[E0597]: `i` does not live long enough
--> src/lib.rs:15:15
|
15 | print_it(&i);
| ---------^^--
| | |
| | borrowed value does not live long enough
| argument requires that `i` is borrowed for `'static`
16 | }
| - `i` dropped here while still borrowed