下面是一个用到RC和RefCell的例子:
例子模拟餐厅的菜单的传递,菜单数据Order是Rc<RefCell<Vec<TableOrder>>>,一个RC引用了RefCell,RefCell又引用了一个集合了TableOrder结构体的Vec容器。外层的RC用于分享引用,但是RC是不可变引用,所以嵌套RefCell,我们不需要改变Rc里面的RefCell,但可以通过RefCell改变第三层数据。
*1 创建一个Order类型;
*2 为三类餐厅员工克隆该引用,因为Ref中的数据是可以共享的;
*3 改变第三层数据Vec,因为RefCell中的数据总是可变的,但是记得要把改变放在括号里,因为RefCell的借用规则是可变引用不可以和和其他引用共存,否则之前的引用会被析构掉,
*4 打印数据。
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
#[derive(Debug)]
enum MenuItem {
Drink,
Salad,
}
#[derive(Debug)]
struct ItemOrder {
item: MenuItem,
quantity: u32,
}
#[derive(Debug)]
struct TableOrder {
items: Vec<ItemOrder>,
}
fn new_table_order() ->TableOrder {
TableOrder {
items: vec![ItemOrder {
item: MenuItem::Drink,
quantity: 1,
}],
}
}
type Order = Rc<RefCell<Vec<TableOrder>>>;
#[derive(Debug)]
struct Chef(Order);
#[derive(Debug)]
struct Staff(Order);
#[derive(Debug)]
struct Accounting(Order);
fn main() {
// *1
let orders:Order = Rc::new(RefCell::new(vec![]));
// *2
let chef = Chef(Rc::clone(&orders));
let staff = Staff(Rc::clone(&orders));
let account = Accounting(Rc::clone(&orders));
// *3
let order = new_table_order();
{ (*orders).borrow_mut().push(order); }
// *4
dbg!(chef.0.borrow());
dbg!(staff.0.borrow());
dbg!(account.0.borrow());
}
Refcell在运行时检查借用规则,引用具有无需关注数据本身的可变性,单一所有者。
Box在编译时检查借用规则,Box借用时只移动数据数据,所以是单一所有者。
Rc在编译时检查借用规则,多个引用所有权。