九、标准库 - 智能指针
Published on
Box
Box是最简单的智能指针,它在堆上分配内存。Box只能有一个持有者,类似于C++的std::unique_ptr。Box没有性能开销,同时也没有额外功能。一般在以下情况下使用
- 要使用一个在编译期无法知道大小的类型
- 要转换大量数据的所有权但是不想拷贝数据
- 要使用实现了某个特性,但并不关心其具体类型的类型
// 声明一个Box并储存一个值
let a = Box::new(5);
// 取Box中储存的值(解引用,需要实现Deref特性)
let b = *a;
// 强制解引
println!("a = {}", a);
// 提前释放内存(可自动释放,需要实现Drop特性)
drop(a);
Rc
Rc是带引用计数的智能指针,可以有多个持有者,类似于C++的std::shared_ptr。
// 声明一个Rc并储存一个值
let rc_a: Rc<String> = Rc::new("Rc examples".to_string());
// 复制指针(底层数据不变,引用计数+1)
let rc_b: Rc<String> = Rc::clone(&rc_a);
// 查看引用计数
println!("Reference Count of rc_a: {}", Rc::strong_count(&rc_a));
// 判断两个Rc是否指向同一数据
println!("rc_a and rc_b are equal: {}", rc_a.eq(&rc_b));
// 通过Rc直接使用底层数据的方法
println!("Length of the value inside rc_a: {}", rc_a.len());
RefCell
使用以上智能指针时,会在编译期检查所有权借用规则(同时只能有一个可变引用或任意个不可变引用),检查不通过则编译失败。RefCell与Box类似,但是在运行时才检查借用规则,如果检查不通过则会panic。
// 使用RefCell指向一个Vec
let v = RefCell::new(vec![1, 2, 3, 4]);
// 可变借用
let mut a = v.borrow_mut();
a.push(5);
// 不可变借用
let b = v.borrow();
println!("{}", b.len());
Weak
Weak指针不增加底层数据的strong_count,只增加其weak_count,因而不影响底层数据的释放。它用于防止形成死锁,类似于C++的std::weak_ptr。
// 声明一个强指针
let strong = Rc::new(100);
// 将其转换为弱指针
let weak = Rc::downgrade(&strong);
// 在使用弱指针前,需要获取对应的强指针,如果该指针已释放,则返回None
let opt: Option<Rc<i32>> = weak.upgrade();
Arc
类似于Rc,用于多线程环境。
let apple = Arc::new("the same apple");
for _ in 0..10 {
let apple = Arc::clone(&apple);
thread::spawn(move || {
println!("{:?}", apple);
});
}