基礎知識

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

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

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

標準の型

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

UnsafeCell

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

UnsafeCell 以外

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

代表的な型の一覧

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

サンプル

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


use std::cell::Cell;

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