名前は、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);