Rc<T>
Rc<T>的作用就是对value的引用计数,来决定指向的对象是否还在被使用,如果没有了引用,就可以被回收了
Rc<T>只在单线程的场景适用
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
let b = Cons(3, Box::new(a));
let c = Cons(4, Box::new(a));
}
这段代码会报错,因为a已经move到了b.
error[E0382]: use of moved value: `a`
--> src/main.rs:11:30
|
9 | let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
| - move occurs because `a` has type `List`, which does not implement the `Copy` trait
10 | let b = Cons(3, Box::new(a));
| - value moved here
11 | let c = Cons(4, Box::new(a));
| ^ value used here after move
为了给a能添加多个指针,我们可以使用Rc::clone的方式
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a));
}
每次使用Rc::clone引用计数都会+1,离开作用域就会-1,向下面这样:
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a));
println!("count after creating b = {}", Rc::strong_count(&a));
{
let c = Cons(4, Rc::clone(&a));
println!("count after creating c = {}", Rc::strong_count(&a));
}
println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}
输出:
count after creating a = 1
count after creating b = 2
count after creating c = 3
count after c goes out of scope = 2
总之,使用这种方式,可以让一个值拥有多个所有者,在只要存在所有者的情况下值就不会消失,但是Rc创造出来的都是不可变的引用,如果想要可变,可以使用RefCell
Arc<T>
和Rc<T>不一样的是,Arc<T>是一个线程安全的引用计数,指向堆上,使用clone可以对堆上的数据加一个新的引用
Arc<T>创建出来的引用也都是不可变的,如果想要可以