Refining Ch06.

This commit is contained in:
rust-lang.xfoss.com 2023-12-15 17:27:22 +08:00
parent 6bae7063bf
commit a36eb064b2

View File

@ -5,10 +5,12 @@
结构体提供了一种将相关字段和数据,分组在一起的方法,比如有着 `width``height` 两个字段的 `Rectangle`,而枚举则提供了一种,表示一个值是一组可能值之一的方法。例如,我们可能想表达,`Rectangle` 是一组其中还包括 `Circle``Triangle` 等可能形状之一。为此Rust 允许我们,将这些可能性编码为某个枚举。 结构体提供了一种将相关字段和数据,分组在一起的方法,比如有着 `width``height` 两个字段的 `Rectangle`,而枚举则提供了一种,表示一个值是一组可能值之一的方法。例如,我们可能想表达,`Rectangle` 是一组其中还包括 `Circle``Triangle` 等可能形状之一。为此Rust 允许我们,将这些可能性编码为某个枚举。
我们来看看我们可能想在代码中表达的一种情况,看看为什么在这种情况下,枚举要比结构体更有用、更合适。假设我们需要处理 IP 地址。目前IP 地址使用两种主要标准:第四版和第六版。由于我们的程序只会遇到这两种可能的 IP 地址,因此我们可以枚举所有可能的变体,这就是枚举名称的由来。 我们来看看我们可能想在代码中表达的一种情况,看看为什么在这种情况下,枚举要比结构体更有用、更合适。假设我们需要处理 IP 地址。目前,有两种用于 IP 地址的主要标准:版本四和版本六。由于我们的程序只会遇到这两种可能的 IP 地址,因此我们可以 *枚举出* 所有可能的变种,这就是枚举名称的由来。
任何 IP 地址都只能是版本四或版本六的地址,而不会同时两个都是。由于枚举值只能是枚举变种之一,那么 IP 地址的这个属性令到枚举数据结构the enum data structure恰当起来。而版本四和版本六两种地址从根本上说都是 IP 地址,那么在代码对适用于任意类别 IP 地址的情形加以处理时,版本四和版本六地址都应当作同一类型对待。
任何 IP 地址都可以是版本 4 或版本 6 的地址但不能同时是这两种地址。IP 地址的这一属性,使得枚举这种数据结构非常合适,因为某个枚举值,只能是其变体之一。从根本上说,版本 4 和版本 6 地址,都仍是 IP 地址,因此当代码在处理适用于任何类别的 IP 地址的情况时,他们应被视为同一类型。
可以通过定义一个 `IpAddrKind` 枚举,并列出某个 IP 地址可以是的那些可能种类,即 `V4``V6`,我们就可以在咱们的代码中,表达这一概念。下面就是这个枚举的那些变种:
在代码中,可通过定义一个 `IpAddrKind` 枚举,并列出 IP 地址可能的类别,即 `V4``V6`,来表达这个概念。下面就是该枚举的变种:
```rust ```rust
enum IpAddrKind { enum IpAddrKind {
@ -17,35 +19,41 @@ enum IpAddrKind {
} }
``` ```
现在 `IpAddrKind` 就是一个可在代码中别的地方使用的定制数据类型了 `IpAddrKind` 现在就是一种,我们可以在我们代码的其他地方使用的自定义数据类型
## 枚举 ## 枚举值
**Enum Values** **Enum Values**
可像下面这样,创建出 `IpAddrKind` 两个变种的实例来: 我们可以像下面这样,创建出 `IpAddrKind` 两个变种的实例:
```rust ```rust
let four = IpAddrKind::V4; let four = IpAddrKind::V4;
let six = IpAddrKind::V6; let six = IpAddrKind::V6;
``` ```
请注意,该枚举的两个变种,是在其标识符的命名空间之下的,且这里使用了双冒号将标识符和变种分隔开。由于现在这两个值 `IpAddrKind::V4``IpAddrKind::V6` 都是这同一类型:`IpAddrKind`,因此这就变得有用了。随后就可以,比如,定义一个取任意 `IpAddrKind` 类型值的函数: 请注意,该枚举的两个变种,都是在其标识符下的命名空间中,而我们要使用双冒号,分隔两者。这很有用,因为现在 `IpAddrKind::V4``IpAddrKind::V6` 两个值,属于同一类型:`IpAddrKind`。例如,我们随后就可以定义出一个,取任意 `IpAddrKind` 的函数:
```rust ```rust
fn route(ip_kind: IpAddrKind) {} fn route(ip_kind: IpAddrKind) {}
``` ```
进而就能以这两个变种对这个函数进行调用了:
并且我们可以两个变种,调用这个函数:
```rust ```rust
route(IpAddrKind::V4); route(IpAddrKind::V4);
route(IpAddrKind::V6); route(IpAddrKind::V6);
``` ```
枚举的使用甚至还有更多好处。在还没有一种存储具体 IP 地址 *数据data* 的时候,就要进一步思考一下这里的 IP 地址类型;这是只知道 IP 地址数据为什么 *类别king*。根据在第 5 章中掌握的结构体知识,那么可能很想用下面清单 6-1 中的结构体来解决这个问题。
使用枚举还有更多优势。请再想想我们的 IP 地址类型,目前我们还没有存储具体 IP 地址 *数据* 的方法;我们只知道他是什么 *类别kind*。鉴于咱们刚刚在第 5 章中,学习了结构体,咱们可能会想使用结构体,来解决这个问题,如下清单 6-1 所示。
```rust ```rust
enum IpAddrKind { enum IpAddrKind {
@ -71,7 +79,9 @@ fn main() {
} }
``` ```
*清单 6-1使用结构体 `struct` 来存储 IP 地址的数据与 `IpAddrKind` 变种* *清单 6-1使用结构体 `struct` 存储 IP 地址的数据及 `IpAddrKind` 变种*
这里已定义了有着两个字段的结构体 `IpAddr`:一个类型为 `IpAddrKind` (即先前定义的那个枚举)的 `kind` 字段,以及一个类型为 `String``address` 字段。这里有该结构体的两个实例。第一个是 `home`,而他有着与地址数据 `127.0.0.1` 关联的 `IpAddrKind::V4` 作为其 `kind` 的值。第二个实例为 `loopback`。这个实例则有不同的 `IpAddrKind` 变种作为其 `kind` 的值,即 `V6`,与 `kind` 关联的是地址 `::1`。由于这里使用了结构体将 `kind``address` 值捆绑在一起,因此现在这个 `IpAddrKind` 的变种就与那个 `String` 值关联起来了。 这里已定义了有着两个字段的结构体 `IpAddr`:一个类型为 `IpAddrKind` (即先前定义的那个枚举)的 `kind` 字段,以及一个类型为 `String``address` 字段。这里有该结构体的两个实例。第一个是 `home`,而他有着与地址数据 `127.0.0.1` 关联的 `IpAddrKind::V4` 作为其 `kind` 的值。第二个实例为 `loopback`。这个实例则有不同的 `IpAddrKind` 变种作为其 `kind` 的值,即 `V6`,与 `kind` 关联的是地址 `::1`。由于这里使用了结构体将 `kind``address` 值捆绑在一起,因此现在这个 `IpAddrKind` 的变种就与那个 `String` 值关联起来了。