|
|
@ -1,8 +1,8 @@
|
|
|
|
## `Box<T>` 在堆上存储数据,并且可确定大小
|
|
|
|
## 使用`Box <T>`指向堆上的数据
|
|
|
|
|
|
|
|
|
|
|
|
> [ch15-01-box.md](https://github.com/rust-lang/book/blob/master/src/ch15-01-box.md)
|
|
|
|
> [ch15-01-box.md](https://github.com/rust-lang/book/blob/master/src/ch15-01-box.md)
|
|
|
|
> <br>
|
|
|
|
> <br>
|
|
|
|
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
|
|
|
|
> commit a203290c640a378453261948b3fee4c4c6eb3d0f
|
|
|
|
|
|
|
|
|
|
|
|
最简单直接的智能指针是 *box*,其类型是 `Box<T>`。 box 允许你将一个值放在堆上而不是栈上。留在栈上的则是指向堆数据的指针。如果你想回顾一下栈与堆的区别请参考第四章。
|
|
|
|
最简单直接的智能指针是 *box*,其类型是 `Box<T>`。 box 允许你将一个值放在堆上而不是栈上。留在栈上的则是指向堆数据的指针。如果你想回顾一下栈与堆的区别请参考第四章。
|
|
|
|
|
|
|
|
|
|
|
@ -16,7 +16,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
### 使用 `Box<T>` 在堆上储存数据
|
|
|
|
### 使用 `Box<T>` 在堆上储存数据
|
|
|
|
|
|
|
|
|
|
|
|
在开始 `Box<T>` 的用例之前,让我们熟悉一下语法和如何与储存在 `Box<T>` 中的值交互。
|
|
|
|
在讨论 `Box<T>` 的此用例之前,让我们熟悉一下语法以及如何与储存在 `Box<T>` 中的值进行交互。
|
|
|
|
|
|
|
|
|
|
|
|
示例 15-1 展示了如何使用 box 在堆上储存一个 `i32`:
|
|
|
|
示例 15-1 展示了如何使用 box 在堆上储存一个 `i32`:
|
|
|
|
|
|
|
|
|
|
|
@ -35,11 +35,11 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
|
|
将一个单独的值存放在堆上并不是很有意义,所以像示例 15-1 这样单独使用 box 并不常见。将像单个 `i32` 这样的值储存在栈上,也就是其默认存放的地方在大部分使用场景中更为合适。让我们看看一个不使用 box 时无法定义的类型的例子。
|
|
|
|
将一个单独的值存放在堆上并不是很有意义,所以像示例 15-1 这样单独使用 box 并不常见。将像单个 `i32` 这样的值储存在栈上,也就是其默认存放的地方在大部分使用场景中更为合适。让我们看看一个不使用 box 时无法定义的类型的例子。
|
|
|
|
|
|
|
|
|
|
|
|
### box 允许创建递归类型
|
|
|
|
### Box 允许创建递归类型
|
|
|
|
|
|
|
|
|
|
|
|
Rust 需要在编译时知道类型占用多少空间。一种无法在编译时知道大小的类型是 **递归类型**(*recursive type*),其值的一部分可以是相同类型的另一个值。这种值的嵌套理论上可以无限的进行下去,所以 Rust 不知道递归类型需要多少空间。不过 box 有一个已知的大小,所以通过在循环类型定义中插入 box,就可以创建递归类型了。
|
|
|
|
Rust 需要在编译时知道类型占用多少空间。一种无法在编译时知道大小的类型是 **递归类型**(*recursive type*),其值的一部分可以是相同类型的另一个值。这种值的嵌套理论上可以无限的进行下去,所以 Rust 不知道递归类型需要多少空间。不过 box 有一个已知的大小,所以通过在循环类型定义中插入 box,就可以创建递归类型了。
|
|
|
|
|
|
|
|
|
|
|
|
让我们探索一下 *cons list*,一个函数式编程语言中的常见类型,来展示这个(递归类型)概念。除了递归之外,我们将要定义的 cons list 类型是很直白的,所以这个例子中的概念在任何遇到更为复杂的涉及到递归类型的场景时都很实用。
|
|
|
|
让我们探索一下 *cons list*,一个函数式编程语言中的常见类型,来展示这个(递归类型)概念。除了递归之外,我们将要定义的 cons list 类型是很直白的,所以这个例子中的概念,在任何遇到更为复杂的涉及到递归类型的场景时都很实用。
|
|
|
|
|
|
|
|
|
|
|
|
#### cons list 的更多内容
|
|
|
|
#### cons list 的更多内容
|
|
|
|
|
|
|
|
|
|
|
@ -47,7 +47,7 @@ Rust 需要在编译时知道类型占用多少空间。一种无法在编译时
|
|
|
|
|
|
|
|
|
|
|
|
cons 函数的概念涉及到更常见的函数式编程术语;“将 *x* 与 *y* 连接” 通常意味着构建一个新的容器而将 *x* 的元素放在新容器的开头,其后则是容器 *y* 的元素。
|
|
|
|
cons 函数的概念涉及到更常见的函数式编程术语;“将 *x* 与 *y* 连接” 通常意味着构建一个新的容器而将 *x* 的元素放在新容器的开头,其后则是容器 *y* 的元素。
|
|
|
|
|
|
|
|
|
|
|
|
cons list 的每一项都包含两个元素:当前项的值和下一项。其最后一项值包含一个叫做 `Nil` 的值并没有下一项。cons list 通过递归调用 `cons` 函数产生。代表递归的终止条件(base case)的规范名称是 `Nil`,它宣布列表的终止。注意这不同于第六章中的 “null” 或 “nil” 的概念,他们代表无效或缺失的值。
|
|
|
|
cons list 的每一项都包含两个元素:当前项的值和下一项。其最后一项值包含一个叫做 `Nil` 的值且没有下一项。cons list 通过递归调用 `cons` 函数产生。代表递归的终止条件(base case)的规范名称是 `Nil`,它宣布列表的终止。注意这不同于第六章中的 “null” 或 “nil” 的概念,他们代表无效或缺失的值。
|
|
|
|
|
|
|
|
|
|
|
|
注意虽然函数式编程语言经常使用 cons list,但是它并不是一个 Rust 中常见的类型。大部分在 Rust 中需要列表的时候,`Vec<T>` 是一个更好的选择。其他更为复杂的递归数据类型 **确实** 在 Rust 的很多场景中很有用,不过通过以 cons list 作为开始,我们可以探索如何使用 box 毫不费力的定义一个递归数据类型。
|
|
|
|
注意虽然函数式编程语言经常使用 cons list,但是它并不是一个 Rust 中常见的类型。大部分在 Rust 中需要列表的时候,`Vec<T>` 是一个更好的选择。其他更为复杂的递归数据类型 **确实** 在 Rust 的很多场景中很有用,不过通过以 cons list 作为开始,我们可以探索如何使用 box 毫不费力的定义一个递归数据类型。
|
|
|
|
|
|
|
|
|
|
|
@ -165,4 +165,4 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
|
|
box 只提供了间接存储和堆分配;他们并没有任何其他特殊的功能,比如我们将会见到的其他智能指针。它们也没有这些特殊功能带来的性能损失,所以他们可以用于像 cons list 这样间接存储是唯一所需功能的场景。我们还将在第十七章看到 box 的更多应用场景。
|
|
|
|
box 只提供了间接存储和堆分配;他们并没有任何其他特殊的功能,比如我们将会见到的其他智能指针。它们也没有这些特殊功能带来的性能损失,所以他们可以用于像 cons list 这样间接存储是唯一所需功能的场景。我们还将在第十七章看到 box 的更多应用场景。
|
|
|
|
|
|
|
|
|
|
|
|
`Box<T>` 类型是一个智能指针,因为它实现了 `Deref` trait,它允许 `Box<T>` 值被当作引用对待。当 `Box<T>` 值离开作用域时,由于 `Box<T>` 类型 `Drop` trait 的实现,box 所指向的堆数据也会被清除。让我们更详细的探索一下这两个 trait;这些 trait 在本章余下讨论的其他智能指针所提供的功能中将会更为重要。
|
|
|
|
`Box<T>` 类型是一个智能指针,因为它实现了 `Deref` trait,它允许 `Box<T>` 值被当作引用对待。当 `Box<T>` 值离开作用域时,由于 `Box<T>` 类型 `Drop` trait 的实现,box 所指向的堆数据也会被清除。让我们更详细的探索一下这两个 trait。这两个 trait 对于在本章余下讨论的其他智能指针所提供的功能中,将会更为重要。
|
|
|
|