智能指针
智能指针是一种数据结构,其行为与指针类似,有额外的元数据和功能。
引用计数(reference counting)智能指针类型,通过记录所有者的数量,使一份数据被多个所有者同时持有,并在没任何所有者时自动清理数据。
其中引用只借用数据,而智能指针常拥有所指向的数据。如智能指针String 和 Vec
智能指针的实现:
- 智能指针通常使用 struct 实现, 并且实现了Deref和Drop这两个trait
- Deref trait: 允许智能指针 struct 的实例像引用一样使用
- Drop trait: 允许你自定义当智能指针实例走出作用域时的代码
标准库中常见的智能指针
- Box
:在heap内存上分配值 - Rc
:启用多重所有权的引用计数类型 - Ref
和 RefMut ,通过 RefCell 访问:在运行时而不是编译时强制借用规则的类型
其他内容:
- 内部可变模式(inferior mutability pattern):不可变类型暴露出可修改其内部值的 API
- 引用循环(reference cycles) 它们如何泄露内存,以及如何防止其发生
使用Box<T>
指向Heap上的数据
Box<T>
是最简单的智能指针,允许在heap上存储数据,形式为在stack上有一指针类型,存放了指向Heap数据的地址,无性能开销,也无其它额外功能,但实现了Deref trait和Drop trait,所以是智能指针。
Box<T>
的常用场景
- 在编译时,某类型的大小无法确定,但使用该类型时,上下文却需要知道确切大小
- 有大量数据,需要移交所有权,但需确保在操作时数据不会被复制
- 在使用某个值时,只关心是否实现了特定的trait,而不关心具体类型
fn main() {
let a = Box::new(3); // 3存在堆里
println!("{}", a);
} // 至此a的生命周期结束,会自动释放stack的指针,以及释放heap的数据内存
使用Box赋能递归类型
在编译时,rust需要知道一个类型所占的内存空间大小,而递归类型的大小无法在编译时确定,但Box类型的大小确定,在递归类型中使用Box就可解决上述问题。在函数式语言中叫Cons List。
使用Box来获得确定大小的递归类型
Box<T>
是一指针,指针本身的大小是固定的,指向的heap数据大小可不确定,这样编译时便可知需要多少内存。实际上就是c/c++语言中结构体和类中包含指针类型。
Box<T>
:
- 只提供了“间接”存储和heap内存分配的功能
- 没有其它额外功能也没有性能开销
- 适用于需要“间接”存储的场景,如Cons List
- 实现了Deref trait(使得能当引用处理) 和Drop trait(自动释放)
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
enum List {
Cons(i32, Box<List>),
Nil,
}