基礎知識

内部可変性のある型は、可変と指定されていなくても、特例として値を変更できる。

これは例えば、不変参照により共有される値の更新などで必要となる。

ただし、内部可変性を乱用するとコードが読みにくくなるので注意が必要。

標準の型

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

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);
}