可変な静的変数

不変の静的変数を読み取るのは安全です:

// 著作権 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

static HELLO_WORLD: &str = "Hello, world!";

fn main() {
    println!("HELLO_WORLD: {HELLO_WORLD}");
}

しかし、可変な静的変数の読み書きは unsafe です。複数のスレッドが同期なしに同時にアクセスでき、その結果データ競合が発生しうるためです。

可変な静的変数を健全に使用するには、コンパイラの助けなしに並行性について考察する必要があります:

// 著作権 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

static mut COUNTER: u32 = 0;

fn add_to_counter(inc: u32) {
    // SAFETY: `COUNTER` にアクセスしうる他のスレッドは存在しません。
    unsafe {
        COUNTER += inc;
    }
}

fn main() {
    add_to_counter(42);

    // SAFETY: `COUNTER` にアクセスしうる他のスレッドは存在しません。
    unsafe {
        dbg!(COUNTER);
    }
}
  • ここでのプログラムは、シングルスレッドであるため健全です。しかし、Rust コンパイラは関数を個別に推論するため、そのことを前提にはできません。unsafe を取り除いて、複数のスレッドから可変な静的変数にアクセスすることが未定義動作であるとコンパイラがどのように説明するか確認してみてください。
  • 2024 Rust edition ではさらに踏み込み、参照経由で可変な静的変数にアクセスすることがデフォルトでエラーになります。
  • 可変な静的変数を使うのが良い考えであることはめったになく、代わりに内部可変性を使うべきです。
  • ヒープアロケータを実装する場合や一部の C API を扱う場合など、低レベルな no_std コードでは必要になることもあります。その場合は、参照ではなくポインタを使うべきです。