27_rust_智能指针

发布时间 2023-11-12 00:52:08作者: 00lab

智能指针

智能指针是一种数据结构,其行为与指针类似,有额外的元数据和功能。
引用计数(reference counting)智能指针类型,通过记录所有者的数量,使一份数据被多个所有者同时持有,并在没任何所有者时自动清理数据。
其中引用只借用数据,而智能指针常拥有所指向的数据。如智能指针String 和 Vec都拥有一片内存区域, 且允许用户对其操作 还拥有元数据 (例如容量等),可提供额外的功能或保障(String保障其数据是合法的UTF-8编码)。

智能指针的实现:

  • 智能指针通常使用 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,
}