名前は、Reference Counted (参照カウント)の略。所有権を共有する為に使います。
Rc<T>
はシングルスレッド用のカウンタを持つポインターでヒープ上で管理され、T
値に対する複数の所有権(参照じゃない変数)を取得できます。ただし、Rc<T>
だけで使う場合はT
は読み込み専用的な扱いになります。
例えばString
で見てみると、この方はCopy
を継承していないので、所有権は 1 つの変数しか持てません。
// Rust Playground
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=639fa328bea148a12b2130950f878216
fn main() {
let str = String::from("foo");
// --- move occurs because `str` has type `std::string::String`,
// which does not implement the `Copy` trait
let _a = str;
// --- value moved here
let _b = str;
// ^^^ value used here after move
}
以下のように Rc で囲むと、これを回避できます。
// Rust Playground
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c8c9b503dc3d49e64d57361c1a2f356f
use std::rc::Rc;
fn main() {
let rc_str = Rc::new(String::from("foo"));
let _a = rc_str.clone();
let _b = rc_str.clone();
}
Rc
はT
に変換できるDeref
を実装してる為、デストラクタによって簡単にT
に変換できます。
上記の_a
と_b
は以下によって値が同じものだと分かります。
println!("{:p}", &*_a); // 0x55c9df807a70
println!("{:p}", &*_b); // 0x55c9df807a70
インスタンスメソッド
以下のようなものがあります。
clone
所有権の共有と参照カウンタの加算strong_count
今の参照数を取得できます。
let thirty_three: Rc = Rc::new(33);
{
let cloned = thirty_three.clone();
// `thirty_three` と `cloned` は同じ
assert!(thirty_three.eq(&cloned));
assert_eq!(Rc::strong_count(&thirty_three), 2);
// スコープを抜けるので参照カウンタを -1 する
}
assert_eq!(Rc::strong_count(&thirty_three), 1);