著者は最近(2024/07/02時点)、Rustに触れ始めた初学者です。
Rustにおける値の扱い方でヒープメモリを用いる『Box』や、共有参照を扱う『RC』と『Arc』などで何を使えばよいか迷うことが多いため、自分なりの理解でまとめています。
ヒープメモリの使用(Box)
Box
let a = Box::new(5);
特徴
- 単一の所有者。
- 値をヒープに確保し、そのポインタを持つ。
- コンパイル時に所有権借用のルールを守る。
用途
- 値のヒープ確保が必要な場合。
- サイズの異なる型を同一のコレクションに格納する場合。
- 再帰的なデータ構造を作成する場合
所有権の共有(RC, Arc)
RC
let a = Rc::new(5);
let b = Rc::clone(&a);
特徴
- 単一スレッド内での共有所有権。
- 不変の値に対する参照カウント。
- スレッドセーフではない。
用途
- 単一のスレッドで複数の所有者が必要な場合。
- ツリー構造やグラフ構造など、複数の部分が同じデータを参照する場合。
Arc
let a = Arc::new(5);
let b = Arc::clone(&a);
特徴
- 複数のスレッドでの共有所有権。
- 不変の値に対する参照カウント。
- スレッドセーフ。
用途
- マルチスレッド環境で複数の所有者が必要な場合。
- スレッド間で安全にデータを共有する場合。
単一スレッドでの内部可変性(Cell, RefCell)
Cell
let a = Cell::new(5);
a.set(10);
特徴
- 単一スレッド内での内部可変性を提供。
- 値を借用せずに変更可能。
- コピー可能な型に対して使用(
Copy
トレイト)。
用途
- 簡単な内部可変性が必要な場合。
- 参照を取らずにデータを変更する必要がある場合。
RefCell
let a = RefCell::new(5);
*ref_cell.borrow_mut() = 10;
特徴
- 単一スレッド内での内部可変性を提供。
- 実行時に借用ルールをチェック(コンパイル時ではなく)。
-
Ref
とRefMut
で不変および可変借用を管理。
用途
- 複雑な内部可変性が必要な場合。
- ライフタイムや借用チェッカがコンパイル時に許可しないが、論理的には安全な場合。
マルチスレッドでの内部可変性(Mutex, RwLock)
Mutex
let a = Mutex::new(5);
{
let mut b= a.lock().unwrap();
*num = 10;
}
特徴
- マルチスレッド環境での排他制御を提供。
- データへのアクセスを一度に一つのスレッドに限定。
-
lock
メソッドでデータへの排他アクセスを取得。
用途
- スレッド間でデータの一貫性を保つ必要がある場合。
- 同期が必要な場合。
RwLock
let a = RwLock::new(5);
{
let b = rw.read().unwrap();
println!("{}", *b);
}
{
let mut c = rw.write().unwrap();
*c = 10;
}
特徴
- マルチスレッド環境での排他制御と共有読み取りを提供。
- 複数のスレッドが同時に読み取り可能。
- 書き込みは一度に一つのスレッドのみ。
用途
- 読み取りが多く、書き込みが少ない場合。
- 読み取りと書き込みの操作が明確に区別できる場合。
よく使う組み合わせ
Rc
+ Cell
- 単一スレッド内で、参照カウントされたデータの内部可変性が必要な場合に使用されます。
-
Rc
はデータの共有所有権を提供し、Cell
は内部可変性を提供します。
Rc
+ RefCell
- 単一スレッド内での複数所有者によるデータの共有と内部可変性を提供するために使用されます。
-
Rc
は参照カウント型のスマートポインタで、RefCell
は実行時に借用チェックを行う可変データを提供します。
Arc
+ Mutex
- マルチスレッド環境で、共有データに対する排他アクセスを提供するために使用されます。
-
Arc
はデータの共有所有権を提供し、Mutex
はデータへの排他アクセスを管理します。
Arc
+ RwLock
- マルチスレッド環境で、複数のスレッドがデータを読み取り可能で、書き込みは排他制御したい場合に使用されます。
-
Arc
はデータの共有所有権を提供し、RwLock
は複数の読み取りと単一の書き込みを管理します。