可変なstatic変数

Rustでは、static変数を可変(mutable)にすることもできますが、その場合はunsafeブロック内で操作する必要があります。以下は可変なstatic変数の例です。

static mut COUNTER: i32 = 0;

fn main() {
    unsafe {
        COUNTER += 1;
        println!("COUNTER: {}", COUNTER);
    }
}

この例では、COUNTERという可変な静的変数が宣言され、unsafeブロック内でその値を変更しています。

unsafeてなに

unsafeブロックを使用することで、通常のRustでは許されない操作を実行することができます。

メモリ安全性とデータ競合

Rustは、メモリ安全性を保証するために、所有権と借用のルールを厳格に適用します。 しかし、可変なstatic変数はこれらのルールを回避するため、複数のスレッドから同時にアクセスされる可能性があります。 これにより、データ競合や未定義動作が発生するリスクがあります。

unsafeの必要性

可変なstatic変数を使用する場合、Rustのコンパイラはその安全性を保証できません。 そのため、プログラマが手動で安全性を保証する必要があります。 これを示すために、unsafeブロック内で操作を行う必要があります。 unsafeブロックは、プログラマがこのコードの安全性を確認し、責任を持つことを意味します。

unsafeの初心者の理解

static変数を可変にする場合、コンパイラがメモリの安全性を保証できないようですね。 プログラマがunsafeなのはわかってる!!と明示的に書く必要がルール的にあるのですね!

unsafeを利用しない可変なstatic変数

critical_sectionというクレートを利用すればunsafeを使わずに可変なstatic変数を定義可能です。

static COUNTER: critical_section::Mutex<core::cell::RefCell<i32>> =
    critical_section::Mutex::new(core::cell::RefCell::new(0));

fn main() {
    critical_section::with(|cs| {
        let mut counter = COUNTER.borrow(cs).borrow_mut();
        *counter += 1;
        println!("COUNTER: {}", counter);
    });
}

ですが、critical_secton::withといった排他処理をする必要があるため、unsafeに比べて処理がかかります。一方で、安全生は確保されます。