Rust中的Rc
2023-03-07 本文已影响0人
天之見證
特点
-
单线程的引用计数
-
不可变引用
-
非线程安全,线程安全请使用
Arc
循环引用问题
仅仅使用Rc
会遇到循环引用的问题,导致指针没法被释放掉,此时可以通过Weak
来打破这种引用。如下图所示:
Weak
Weak
可以看作是一种特殊的Rc
,它引用对象的时候并不会增加计数,也不保证它对应的对象一直有效。主要用在:
-
保有一个
Rc
管理的空间的临时引用,但并不会防止其被释放 -
循环引用
没有自解引用
Rc,Weak相互转换
use std::rc::Rc;
use std::ptr;
let strong = Rc::new("hello".to_owned());
let weak = Rc::downgrade(&strong);
自解引用
Rc<T>
是自动解引用的,所以可以直接使用T
的方法。所以一般调用Rc
自身的方法的时候,经常采用类名调用的方式:
use std::rc::Rc;
let rc = Rc::new(());
let rc2 = Rc::clone(&rc);
let rc3 = rc.clone(); // 这种调用方式也是可以的
示例
场景一
一个Owner
有一堆小玩意儿,我们先让我们的小玩意儿指向它们的Owner
,但是这种拥有又不是唯一的,即一个Owner
只有1个小玩意儿,一个Owner
有多个小玩意儿,此时这些小玩意儿就需要共享这个Owner
use std::rc::Rc;
struct Owner {
name: String,
// ...other fields
}
struct Gadget {
id: i32,
owner: Rc<Owner>,
// ...other fields
}
fn main() {
// Create a reference-counted `Owner`.
let gadget_owner: Rc<Owner> = Rc::new(
Owner {
name: "Gadget Man".to_string(),
}
);
// Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc<Owner>`
// gives us a new pointer to the same `Owner` allocation, incrementing
// the reference count in the process.
let gadget1 = Gadget {
id: 1,
owner: Rc::clone(&gadget_owner),
};
let gadget2 = Gadget {
id: 2,
owner: Rc::clone(&gadget_owner),
};
// Dispose of our local variable `gadget_owner`.
drop(gadget_owner);
// Despite dropping `gadget_owner`, we're still able to print out the name
// of the `Owner` of the `Gadget`s. This is because we've only dropped a
// single `Rc<Owner>`, not the `Owner` it points to. As long as there are
// other `Rc<Owner>` pointing at the same `Owner` allocation, it will remain
// live. The field projection `gadget1.owner.name` works because
// `Rc<Owner>` automatically dereferences to `Owner`.
println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);
// At the end of the function, `gadget1` and `gadget2` are destroyed, and
// with them the last counted references to our `Owner`. Gadget Man now
// gets destroyed as well.
}
场景二
在场景一的基础之上,我们还需要可以从Owner
获取它的小玩意儿
这里其实还隐含着需要修改
Owner
对应的数据
对gadget
类型做如下解释:
由于Owner
被Rc
包裹了,所以gadgets
也要用RefCell
包裹,不然没法进行修改。
因为我们只能获得一个Owner
的不可变引用
use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
struct Owner {
name: String,
gadgets: RefCell<Vec<Weak<Gadget>>>,
// ...other fields
}
struct Gadget {
id: i32,
owner: Rc<Owner>,
// ...other fields
}
fn main() {
// Create a reference-counted `Owner`. Note that we've put the `Owner`'s
// vector of `Gadget`s inside a `RefCell` so that we can mutate it through
// a shared reference.
let gadget_owner: Rc<Owner> = Rc::new(
Owner {
name: "Gadget Man".to_string(),
gadgets: RefCell::new(vec![]),
}
);
// Create `Gadget`s belonging to `gadget_owner`, as before.
let gadget1 = Rc::new(
Gadget {
id: 1,
owner: Rc::clone(&gadget_owner),
}
);
let gadget2 = Rc::new(
Gadget {
id: 2,
owner: Rc::clone(&gadget_owner),
}
);
// Add the `Gadget`s to their `Owner`.
{
let mut gadgets = gadget_owner.gadgets.borrow_mut();
gadgets.push(Rc::downgrade(&gadget1));
gadgets.push(Rc::downgrade(&gadget2));
// `RefCell` dynamic borrow ends here.
}
// Iterate over our `Gadget`s, printing their details out.
for gadget_weak in gadget_owner.gadgets.borrow().iter() {
// `gadget_weak` is a `Weak<Gadget>`. Since `Weak` pointers can't
// guarantee the allocation still exists, we need to call
// `upgrade`, which returns an `Option<Rc<Gadget>>`.
//
// In this case we know the allocation still exists, so we simply
// `unwrap` the `Option`. In a more complicated program, you might
// need graceful error handling for a `None` result.
let gadget = gadget_weak.upgrade().unwrap();
println!("Gadget {} owned by {}", gadget.id, gadget.owner.name);
}
// At the end of the function, `gadget_owner`, `gadget1`, and `gadget2`
// are destroyed. There are now no strong (`Rc`) pointers to the
// gadgets, so they are destroyed. This zeroes the reference count on
// Gadget Man, so he gets destroyed as well.
}