可変なstatic変数
Rustでは、static変数を可変(mutable)にすることもできますが、その場合はunsafeブロック内で操作する必要があります。以下は可変なstatic変数の例です。
static mut COUNTER: i32 = 0; fn main() { unsafe { COUNTER += 1; println!("COUNTER: {}", COUNTER); } }
この例では、COUNTERという可変な静的変数が宣言され、unsafeブロック内でその値を変更しています。
メモリ安全性とデータ競合
Rustは、メモリ安全性を保証するために、所有権と借用のルールを厳格に適用します。 しかし、可変なstatic変数はこれらのルールを回避するため、複数のスレッドから同時にアクセスされる可能性があります。 これにより、データ競合や未定義動作が発生するリスクがあります。
unsafeの必要性
可変なstatic変数を使用する場合、Rustのコンパイラはその安全性を保証できません。 そのため、プログラマが手動で安全性を保証する必要があります。 これを示すために、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に比べて処理がかかります。一方で、安全生は確保されます。