写点什么

5 分钟速读之 Rust 权威指南(二十四)Box

用户头像
码生笔谈
关注
发布于: 2021 年 06 月 17 日
5分钟速读之Rust权威指南(二十四)Box

从本节开始介绍智能指针(smart pointer),智能指针是一些数据结构,它们的行为类似于指针,但拥有额外的元数据和附加功能,引用和智能指针不同,引用是只借用数据的指针;而大多数的智能指针本身就拥有它们指向的数据,也就是具有数据的所有权。

Box<T>

装箱类型(box)使我们可以将数据存储在堆上,并在栈中保留一个指向堆数据的指针。

使用场景

  • 当拥有一个无法在编译时确定大小的类型,但又想要在一个要求固定尺寸的上下文环境中使用这个类型的值时。

  • 当需要传递大量数据的所有权,但又不希望产生大量数据的复制行为时。

  • 当希望拥有一个实现了指定 trait 的类型值,但又不关心具体的类型时。

使用装箱

let b = Box::new(5);println!("{}", b); // 5
复制代码


另外,和其他任何拥有所有权的值一样,装箱会在离开自己的作用域时被释放,包括指针和堆上的数据。

使用装箱定义递归类型

rust 中使用基本类型是无法实现递归的,当然你也可以自行试一下实现一个链表数据结构,过程中必然会得到 rust 的报错,因为 rust 无法确定递归类型的大小,进而无法通过编译。

使用枚举实现链表结构

下面我们使用 rust 尝试实现链表,看一下 rust 的报错:


#[derive(Debug)]enum List {  Cons(i32, List), // error, 递归类型有无限的大小  Nil,}let list = List::Cons(1,  List::Cons(2,    List::Cons(3, List::Nil)  ));println!("{:?}", list);
复制代码


由于 rust 在编译过程中需要知道所有类型的大小,而在运行时递归是无限的,所以在编译过程中无法计算出递归的大小

使用 Box<T>将递归类型的大小固定下来

下面使用 Box<T>类型重新尝试看看如何实现链表:


#[derive(Debug)]enum List {  Node(i32, Box<List>), // 使用Box标记类型  Nil,}let list = List::Node(1,  Box::new(List::Node(2,    Box::new(List::Node(3,      Box::new(List::Nil))    )  )));println!("{:?}", list);// Node(1, Node(2, Node(3, Nil)))
复制代码


因为 Box<T>是一个指针,所以 Rust 可以在编译时就确定一个 Box<T>的具体大小。指针的大小总是恒定的,它不会因为指向数据的大小而产生变化。

结构体实现链表结构

上面使用的枚举来实现链表,我们也可以使用结构体来实现:


#[derive(Debug)]struct Node<T> {  value: T,  next: Box<Option<Node<T>>>}let list = Node {  value: 1,  next: Box::new(Some(Node {    value: 1,    next: Box::new(None)  }))};println!("{:?}", list);// Node { value: 1, next: Some(Node { value: 1, next: None }) }
复制代码


Box 类型比较简单,所以本节内容不多,后面会介绍智能指针相关的 trait,和更多智能指针的类型。

发布于: 2021 年 06 月 17 日阅读数: 6
用户头像

码生笔谈

关注

欢迎关注「码生笔谈」公众号 2018.09.09 加入

前端、Rust干货分享,一起成为更好的Javascripter & Rustacean

评论

发布
暂无评论
5分钟速读之Rust权威指南(二十四)Box