From a36eb064b2486865ee0647003259a0ef5ec96f2f Mon Sep 17 00:00:00 2001 From: "rust-lang.xfoss.com" Date: Fri, 15 Dec 2023 17:27:22 +0800 Subject: [PATCH] Refining Ch06. --- .../defining_an_enum.md | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/enums_and_pattern_matching/defining_an_enum.md b/src/enums_and_pattern_matching/defining_an_enum.md index 22d8fd9..2214e85 100644 --- a/src/enums_and_pattern_matching/defining_an_enum.md +++ b/src/enums_and_pattern_matching/defining_an_enum.md @@ -5,10 +5,12 @@ 结构体提供了一种将相关字段和数据,分组在一起的方法,比如有着 `width` 和 `height` 两个字段的 `Rectangle`,而枚举则提供了一种,表示一个值是一组可能值之一的方法。例如,我们可能想表达,`Rectangle` 是一组其中还包括 `Circle` 和 `Triangle` 等可能形状之一。为此,Rust 允许我们,将这些可能性编码为某个枚举。 -我们来看看我们可能想在代码中表达的一种情况,看看为什么在这种情况下,枚举要比结构体更有用、更合适。假设我们需要处理 IP 地址。目前,IP 地址使用两种主要标准:第四版和第六版。由于我们的程序只会遇到这两种可能的 IP 地址,因此我们可以枚举所有可能的变体,这就是枚举名称的由来。 -任何 IP 地址都只能是版本四或版本六的地址,而不会同时两个都是。由于枚举值只能是枚举变种之一,那么 IP 地址的这个属性,令到枚举数据结构(the enum data structure)恰当起来。而版本四和版本六两种地址,从根本上说都是 IP 地址,那么在代码对适用于任意类别 IP 地址的情形加以处理时,版本四和版本六地址都应当作同一类型对待。 +我们来看看我们可能想在代码中表达的一种情况,看看为什么在这种情况下,枚举要比结构体更有用、更合适。假设我们需要处理 IP 地址。目前,有两种用于 IP 地址的主要标准:版本四和版本六。由于我们的程序只会遇到这两种可能的 IP 地址,因此我们可以 *枚举出* 所有可能的变种,这就是枚举名称的由来。 + +任何 IP 地址都可以是版本 4 或版本 6 的地址,但不能同时是这两种地址。IP 地址的这一属性,使得枚举这种数据结构非常合适,因为某个枚举值,只能是其变体之一。从根本上说,版本 4 和版本 6 地址,都仍是 IP 地址,因此当代码在处理适用于任何类别的 IP 地址的情况时,他们应被视为同一类型。 + +可以通过定义一个 `IpAddrKind` 枚举,并列出某个 IP 地址可以是的那些可能种类,即 `V4` 与 `V6`,我们就可以在咱们的代码中,表达这一概念。下面就是这个枚举的那些变种: -在代码中,可通过定义一个 `IpAddrKind` 枚举,并列出 IP 地址可能的类别,即 `V4` 和 `V6`,来表达这个概念。下面就是该枚举的变种: ```rust enum IpAddrKind { @@ -17,35 +19,41 @@ enum IpAddrKind { } ``` -现在 `IpAddrKind` 就是一个可在代码中别的地方使用的定制数据类型了。 +`IpAddrKind` 现在就是一种,我们可以在我们代码的其他地方使用的自定义数据类型。 -## 枚举取值 +## 枚举值 **Enum Values** -可像下面这样,创建出 `IpAddrKind` 两个变种的实例来: +我们可以像下面这样,创建出 `IpAddrKind` 两个变种的实例: + ```rust let four = IpAddrKind::V4; let six = IpAddrKind::V6; ``` -请注意,该枚举的两个变种,是在其标识符的命名空间之下的,且这里使用了双冒号将标识符和变种分隔开。由于现在这两个值 `IpAddrKind::V4` 与 `IpAddrKind::V6` 都是这同一类型:`IpAddrKind`,因此这就变得有用了。随后就可以,比如,定义一个取任意 `IpAddrKind` 类型值的函数: +请注意,该枚举的两个变种,都是在其标识符下的命名空间中,而我们要使用双冒号,分隔两者。这很有用,因为现在 `IpAddrKind::V4` 和 `IpAddrKind::V6` 两个值,属于同一类型:`IpAddrKind`。例如,我们随后就可以定义出一个,取任意 `IpAddrKind` 的函数: + ```rust fn route(ip_kind: IpAddrKind) {} ``` -进而就能以这两个变种对这个函数进行调用了: + +并且我们可以两个变种,调用这个函数: + ```rust route(IpAddrKind::V4); route(IpAddrKind::V6); ``` -枚举的使用甚至还有更多好处。在还没有一种存储具体 IP 地址 *数据(data)* 的时候,就要进一步思考一下这里的 IP 地址类型;这是只知道 IP 地址数据为什么 *类别(king)*。根据在第 5 章中掌握的结构体知识,那么可能很想用下面清单 6-1 中的结构体来解决这个问题。 + +使用枚举还有更多优势。请再想想我们的 IP 地址类型,目前我们还没有存储具体 IP 地址 *数据* 的方法;我们只知道他是什么 *类别,kind*。鉴于咱们刚刚在第 5 章中,学习了结构体,咱们可能会想使用结构体,来解决这个问题,如下清单 6-1 所示。 + ```rust 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` 值关联起来了。