👶
Rust入門3
Rustは1つのリソースに対して単一の所有者を持たせ、必要な時に借用(一時的な貸与)が基本となっている。
ただ、構成によっては対応しきれないことがある。
そういった場合に活用できるデータ構造の紹介
共同所有者
標準ライブラリに複数の所有者をもたせることができるポインタRc<T>
とRrc<T>
がある。
Rc<T>
Rcポインタを作ると対象のリソースはヒープ領域に格納され、参照カウンタによる管理が行われる。
{
let rc = std::rc::Rc::new(1);
let rc2 = rc.clone();
println!(
"rc count{} rc2 count{}",
std::rc::Rc::strong_count(&rc),
std::rc::Rc::strong_count(&rc2)
);
}
{
let mut rc = std::rc::Rc::new(1);
if let Some(v) = std::rc::Rc::get_mut(&mut rc) {
*v = 5;
}
println!("{}", rc);
{
let rc2 = rc.clone();
// 参照カウントが2以上の場合の場合Noneが返って来て値の変更ができない
println!("{:?} {}", std::rc::Rc::get_mut(&mut rc), rc2);
}
// weakポインタだと参照カウントは増えない
let weak = std::rc::Rc::downgrade(&rc);
println!("rc count{}", std::rc::Rc::strong_count(&rc),);
// weakポインタで共有している場合も値の変更ができない
if let Some(v) = std::rc::Rc::get_mut(&mut rc) {
*v = 10;
println!("{}", rc);
}
{
// 参照カウントを増やして共有する
let rc2 = weak.upgrade().unwrap();
println!("rc2 count{}", std::rc::Rc::strong_count(&rc2));
}
std::mem::drop(rc);
// Rcが解放しているのでNoneになる
println!("{:?}", weak.upgrade());
}
Arc<T>
Rcと似ているがこちらはSyncトレイトを実装しているため複数のスレッドで共有ができる。
ただ、オーバーヘッドが増え速度は遅い。
モジュールはRcと違い std::sync::Arc
になる。
内側のミュータビリティ
コンパイル時の借用チェックを迂回してデータを可変する仕組み。
Rcを使ってcloneした変数がに2つ以上存在する場合は値を変更できないが、この仕組を利用すると変更できるようになる。
let rc = std::rc::Rc::new(std::cell::RefCell::new(1));
// RefCellで包まれているの
println!("{:?}", rc);
// 値を取り出す場合
// borrowで不変の値を取り出す
println!("{:?}", rc.borrow());
// 値を変更する場合
// borrow_mut 可変の参照を取り出す
*rc.borrow_mut() = 5;
println!("{:?}", rc.borrow());
let rc2 = rc.clone();
*rc2.borrow_mut() = 10;
println!("{:?}", rc.borrow());
この様にすることでRcやArcで参照カウントが2以上でも変更できるようになる。
ただ、borrow_mutを行ったとき、他の参照が有効の場合クラッシュする。
クラッシュしないようにする場合 try_borrow_mut
を使う。
これを使うとResult型の値を返し、成否のチェックが行える。
if let Ok(v) = rc2.try_borrow_mut() {
println!("ref OK {}", v);
}
内側のミュータビリティもRc, Arcのようにシングルスレッド、マルチスレッド向けのものがある。
シングルスレッド
- UnsafeCell
安全装置がない。getでポインタを取得して内部の値を書き換える - Cell
UnsafeCellをラップして作られていて、オーバーヘッドがない。set関数を使って内部で値を書き換える。 - RefCell
参照を得ることができる。ただ、借用ルールの検証があるためオーバーヘッドがある。
マルチスレッド
- Mutex
- RxLock
- AtomicUsize
- AtomicI32
など
Discussion