Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

スタティックライフタイム

Rust には、予約済みのライフタイム名がいくつかあります。その 1 つが '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 である string リテラルを作る。

各方法を示す次の例を見てください。

// `'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);
}

'static 参照はプログラムの生存期間の_残り_の間だけ有効であればよいため、プログラムの実行中に作成できます。これを示すために、以下の例では Box::leak を使って 'static 参照を動的に作成しています。この場合、それは間違いなく全期間にわたって生存するわけではなく、リークした時点以降だけ生存します。

extern crate rand;
use rand::Fill;

fn random_vec() -> &'static [u64; 100] {
    let mut rng = rand::rng();
    let mut boxed = Box::new([0; 100]);
    boxed.fill(&mut rng);
    Box::leak(boxed)
}

fn main() {
    let first: &'static [u64; 100] = random_vec();
    let second: &'static [u64; 100] = random_vec();
    assert_ne!(first, second)
}

トレイト境界

トレイト境界としては、その型が非 static な参照を一切含まないことを意味します。例: 受け取る側は望むだけ長くその型を保持でき、それをドロップするまで無効になることはありません。

これは、所有されたデータは常に 'static ライフタイム境界を満たしますが、その所有されたデータへの参照は一般には満たさない、という意味であることを理解するのが重要です。

use std::fmt::Debug;

fn print_it(input: impl Debug + 'static) {
    println!("'static value passed in is: {:?}", input);
}

fn main() {
    // i は所有されており、参照を含まないため、'static である:
    let i = 5;
    print_it(i);

    // おっと、&i は main() のスコープによって定義される
    // ライフタイムしか持たないため、'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

関連項目:

'static 定数