---
title: 'Cell, RefCell, Mutex: 内部可変性'
url: https://doc.liz6.com/ja/rust/04-smart-pointers-and-memory/02-Cell-RefCell-Mutex
locale: ja
area: rust
tags:
- rust
- smart-pointers-and-memory
date: 2026-06-30
modified: 2026-07-16
description: Rustの共有参照(&T)はデフォルトで不変です——Cell/RefCell/Mutexは「共有」を前提として、異なるレベルの内部可変性を提供します。CellはCopy型に適しており（実行時オーバーヘッドなし）、RefCellは借用チェックを実行時に行い（パニックでエラー）、Mutexはスレッドセーフなロック（Send）を追加します。
---

# Cell, RefCell, Mutex: 内部可変性

> Rustの共有参照(`&T`)はデフォルトで不変です——Cell/RefCell/Mutexは「共有」を前提として、異なるレベルの内部可変性を提供します。CellはCopy型に適しており（実行時オーバーヘッドなし）、RefCellは借用チェックを実行時に行い（パニックでエラー）、Mutexはスレッドセーフなロック（Send）を追加します。

## 問題の起源

```rust
let x = 5;
let r = &x;                          // &i32, 不変
// *r = 6;                           // ERROR: &T は変更できない
```

Rustの中核的なルール：共有参照（`&T`）を通じてデータを変更することはできません。これはデータ競合やイテレータの無効化を防ぎます。しかし、**論理的には安全な変更がルールによって拒否される**ことがあります——例えば、計算結果のキャッシュや内部参照カウント。**内部可変性**は、`&self` を保持している間、内部状態を変更することを可能にします。

## Cell<T>: 値の置き換え（Copy型専用）

```rust
use std::cell::Cell;
let c = Cell::new(42);
c.set(100);                          // 内部値を置き換え — &mut self は不要
let val = c.get();                   // コピーして取得
```

`Cell` は内部への参照を返しません——`get()` は常に値をコピーします（`T: Copy` が必要）、`set()` は常に値全体を置き換えます。外部に参照が漏れないため、borrow checker はこれを妨げません。適用シーン：単純な `i32`, `bool`, `enum` のラップ。

## RefCell<T>: 実行時 Borrow Check

```rust
use std::cell::RefCell;
let rc = RefCell::new(vec![1, 2, 3]);
{
    let mut borrow = rc.borrow_mut(); // 実行時: 共有借用がないかチェック
    borrow.push(4);
}                                    // borrow_mut ガードのドロップ → 借用解放
let borrow = rc.borrow();            // 実行時: OK
```

ルールはコンパイル時の borrow checker と同じ——エイリアシング XOR 変更——ですが、チェックは**実行時**に行われます。違反 → `panic!`（コンパイルエラーではありません）。`borrow()` は `Ref<T>`（`&T` への Deref）を返し、`borrow_mut()` は `RefMut<T>`（`&mut T` への Deref）を返します。これらのガードはスコープを抜ける際にドロップされ、内部の借用カウントを解放します。

RefCell は `Sync` ではありません——スレッド間で共有できません。

## Mutex<T>: 内部可変性 + Send + ロック

```rust
use std::sync::Mutex;
let m = Mutex::new(42);
let mut guard = m.lock().unwrap();   // ロックを取得するまでブロック
*guard += 1;                         // DerefMut を通じて内部値にアクセス
drop(guard);                         // ロック解放 (スコープ終了に依存も可)
```

`Mutex` は `RefCell` の内部可変性 + OSロック + `Send` 保証を組み合わせます。内部実装は `UnsafeCell` + OS mutex（Linux では `pthread_mutex_t`）です。`lock()` はロックを取得するまで現在のスレッドをブロックし、`try_lock()` はノンブロッキングで、すぐに `Option<MutexGuard>` を返します。

## 三者比較

| | Cell | RefCell | Mutex |
|---|---|---|---|
| 内部可変性 | Y | Y | Y |
| 参照の返却 | N (コピーのみ) | Y (Ref/RefMut) | Y (MutexGuard) |
| 競合処理 | N/A | panic | block |
| スレッドセーフ | N | N | Y |
| チェック時期 | コンパイル時 (借用なし) | 実行時 (panic) | 実行時 (block) |

## 参考

- **Rust Book**: Chapter 15.5
- **Rustonomicon**: UnsafeCell (すべての内部可変性の背後にあるプリミティブ)

*Keywords: Cell, RefCell, Mutex, interior mutability, UnsafeCell, borrow_mut, runtime borrow check*
