基礎知識

内部可変型では、可変指定がなくても、特例として値を変更できる。

これが安全に行えるのは、他の参照と干渉しない特定のパターンに限られる。

内部可変型を利用すると、本質的でない可変参照による排他性を除去できる。

標準の型

標準で提供される内部可変型について。

UnsafeCell

UnsafeCell は仕様上の特別な型で、ここで紹介しているその他の型の実装の基盤にもなっている。コンパイラはこの型でラップされた値については、たとえ不変とマークされていても、変更されうるものとして扱う。

UnsafeCell 以外

UnsafeCell をそのまま使うのはお勧めできない。なぜなら、それは普段ならば Rust が保証してくれる読込と書込の排他性、それから書込と書込の排他性を失わせる。そのため、バグを書きやすくなる。一方、UnsafeCell を利用して実装された標準型では、他の参照との干渉がおきない理論的背景がある。そのため、可能な限りそれらを採用した方がよい。

代表的な型の一覧

UnsafeCell
危険で特別な型。
Cell
他に影響がないようコピー。
OnceCell
他が読む前に一度だけ初期化。
LazyCell
他が読む前に一度だけ遅延初期化。
RefCell
他が読み書きしていないか動的に確認。
OnceLock
他が読む前に一度だけ初期化 (OnceCell の非同期版)。
LazyLock
他が読む前に一度だけ遅延初期化 (LazyCell の非同期版)。
Mutex
他が使用していないか動的に確認 (RwLock の簡易版)。
RwLock
他が読み書きしていないか動的に確認 (RefCell の非同期版)。
AtomicXXX
他が割り込むスキを与えない (AtomicI32 や AtomicU32 など)。

サンプル

以下では、変数 cell に mut の指定はないが、値を変更できる。


use std::cell::Cell;

fn main() {
    let cell = Cell::new(42);
    cell.set(43);
    assert_eq!(cell.get(), 43);
}