|
|
@ -1,6 +1,6 @@
|
|
|
|
# 枚举
|
|
|
|
# 枚举
|
|
|
|
|
|
|
|
|
|
|
|
枚举(enum或enumeration)允许你通过列举可能的取值来定义一个**枚举类型**,例如扑克牌花色:
|
|
|
|
枚举(enum或enumeration)允许你通过列举可能的成员来定义一个**枚举类型**,例如扑克牌花色:
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
|
enum PokerSuit {
|
|
|
|
enum PokerSuit {
|
|
|
|
Clubs,
|
|
|
|
Clubs,
|
|
|
@ -14,7 +14,7 @@ enum PokerSuit {
|
|
|
|
|
|
|
|
|
|
|
|
再回到之前创建的`PokerSuit`,扑克总共有四种花色,而这里我们枚举出所有的可能值,这也正是`枚举`名称的由来。
|
|
|
|
再回到之前创建的`PokerSuit`,扑克总共有四种花色,而这里我们枚举出所有的可能值,这也正是`枚举`名称的由来。
|
|
|
|
|
|
|
|
|
|
|
|
任何一张扑克,它的花色肯定会落在四种花色中,而且也只会落在其中一个花色上,这种特性非常适合枚举的使用,因为**枚举值**只可能是其中某一个成员。抽象来看,四种花色尽管是不同的花色,但是它们都是扑克花色这个概念,因此当某个函数处理扑克花色时,可以为花色定义一种类型来作为入参。
|
|
|
|
任何一张扑克,它的花色肯定会落在四种花色中,而且也只会落在其中一个花色上,这种特性非常适合枚举的使用,因为**枚举值**只可能是其中某一个成员。抽象来看,四种花色尽管是不同的花色,但是它们都是扑克花色这个概念,因此当某个函数处理扑克花色时,可以把它们当作相同的类型进行传参。
|
|
|
|
|
|
|
|
|
|
|
|
细心的读者应该注意到,我们对之前的`枚举类型`和`枚举值`进行了重点标注,这是因为对于新人来说容易混淆相应的概念,总而言之:
|
|
|
|
细心的读者应该注意到,我们对之前的`枚举类型`和`枚举值`进行了重点标注,这是因为对于新人来说容易混淆相应的概念,总而言之:
|
|
|
|
**枚举类型是一个类型,它会包含所有可能的枚举成员, 而枚举值是该类型中的具体某个成员的实例。**
|
|
|
|
**枚举类型是一个类型,它会包含所有可能的枚举成员, 而枚举值是该类型中的具体某个成员的实例。**
|
|
|
@ -43,7 +43,7 @@ fn print_suit(card: PokerSuit) {
|
|
|
|
|
|
|
|
|
|
|
|
`print_suit`函数的参数类型是`PokerSuit`,因此我们可以把`heart`和`diamond`传给它,虽然`heart`是基于`PokerSuit`下的`Hearts`成员实例化的,但是它是货真价实的`PokerSuit`枚举类型。
|
|
|
|
`print_suit`函数的参数类型是`PokerSuit`,因此我们可以把`heart`和`diamond`传给它,虽然`heart`是基于`PokerSuit`下的`Hearts`成员实例化的,但是它是货真价实的`PokerSuit`枚举类型。
|
|
|
|
|
|
|
|
|
|
|
|
接下来,每张扑克牌除了花色,还有数值。我们想让扑克牌变得更加实用,那么需要给每张牌赋予一个值:`A`(1)-`K`(13),这样就是一张真实的扑克牌了,例如红心A。
|
|
|
|
接下来,我们想让扑克牌变得更加实用,那么需要给每张牌赋予一个值:`A`(1)-`K`(13),这样再加上花色,就是一张真实的扑克牌了,例如红心A。
|
|
|
|
|
|
|
|
|
|
|
|
目前来说,枚举值还不能带有值,因此先用结构体来实现:
|
|
|
|
目前来说,枚举值还不能带有值,因此先用结构体来实现:
|
|
|
|
```rust
|
|
|
|
```rust
|
|
|
@ -159,7 +159,7 @@ struct WriteMessage(String); // 元组结构体
|
|
|
|
struct ChangeColorMessage(i32, i32, i32); // 元组结构体
|
|
|
|
struct ChangeColorMessage(i32, i32, i32); // 元组结构体
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
由于每个结构体都有自己的类型,采用结构体的方式定义这些消息相当于声明了四个结构体,如果一个函数只允许传入一个类型的变量,这样显然是无法实现的,例如某个函数它的功能是接受消息并进行发送,如果使用枚举的方式,只需要一种枚举类型就可以接收不同的消息,但是如果使用结构体,那么该函数久需要接受4个不同的结构体作为参数,这样就复杂了很多。
|
|
|
|
由于每个结构体都有自己的类型,因此我们无法在需要同一类型的地方进行使用,例如某个函数它的功能是接受消息并进行发送,那么用枚举的方式,就可以接收不同的消息,但是用结构体,该函数无法接受4个不同的结构体作为参数。
|
|
|
|
|
|
|
|
|
|
|
|
而且从代码规范角度来看,枚举的实现更简洁,代码内聚性更强,不像结构体的实现,分散在各个地方。
|
|
|
|
而且从代码规范角度来看,枚举的实现更简洁,代码内聚性更强,不像结构体的实现,分散在各个地方。
|
|
|
|
|
|
|
|
|
|
|
@ -222,7 +222,7 @@ let absent_number: Option<i32> = None;
|
|
|
|
|
|
|
|
|
|
|
|
如果使用 `None` 而不是 `Some`,需要告诉 Rust `Option<T>` 是什么类型的,因为编译器只通过 `None` 值无法推断出 `Some` 成员保存的值的类型。
|
|
|
|
如果使用 `None` 而不是 `Some`,需要告诉 Rust `Option<T>` 是什么类型的,因为编译器只通过 `None` 值无法推断出 `Some` 成员保存的值的类型。
|
|
|
|
|
|
|
|
|
|
|
|
当有一个 `Some` 值时,我们就知道这个`Option<T>` 中存在一个值,而这个值保存在 `Some` 中。当有个 `None` 值时,在某种意义上,它跟空值具有相同的意义:这个`Option<T>` 没有一个有效的值。那么,`Option<T>` 为什么就比空值要好呢?
|
|
|
|
当有一个 `Some` 值时,我们就知道存在一个值,而这个值保存在 `Some` 中。当有个 `None` 值时,在某种意义上,它跟空值具有相同的意义:并没有一个有效的值。那么,`Option<T>` 为什么就比空值要好呢?
|
|
|
|
|
|
|
|
|
|
|
|
简而言之,因为 `Option<T>` 和 `T`(这里 `T` 可以是任何类型)是不同的类型,例如,这段代码不能编译,因为它尝试将 `Option<i8>`(`Option<T>`) 与 `i8`(`T`) 相加:
|
|
|
|
简而言之,因为 `Option<T>` 和 `T`(这里 `T` 可以是任何类型)是不同的类型,例如,这段代码不能编译,因为它尝试将 `Option<i8>`(`Option<T>`) 与 `i8`(`T`) 相加:
|
|
|
|
|
|
|
|
|
|
|
@ -249,7 +249,7 @@ not satisfied
|
|
|
|
|
|
|
|
|
|
|
|
换句话说,在对 `Option<T>` 进行 `T` 的运算之前必须将其转换为 `T`。通常这能帮助我们捕获到空值最常见的问题之一:期望某值不为空但实际上为空的情况。
|
|
|
|
换句话说,在对 `Option<T>` 进行 `T` 的运算之前必须将其转换为 `T`。通常这能帮助我们捕获到空值最常见的问题之一:期望某值不为空但实际上为空的情况。
|
|
|
|
|
|
|
|
|
|
|
|
不再担心会错误的使用一个空值,会让我们更放心所编写的代码。为了拥有一个可能为空的值,你必须要显式的将其放入对应类型的 `Option<T>` 中。接着,当使用这个值时,必须明确的处理值为空的情况。只要一个值不是 `Option<T>` 类型,你就 **可以** 安全的认定它的值不为空。这是 Rust 的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加 Rust 代码的安全性。
|
|
|
|
不再担心会错误的使用一个空值,会让你对代码更加有信心。为了拥有一个可能为空的值,你必须要显式的将其放入对应类型的 `Option<T>` 中。接着,当使用这个值时,必须明确的处理值为空的情况。只要一个值不是 `Option<T>` 类型,你就 **可以** 安全的认定它的值不为空。这是 Rust 的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加 Rust 代码的安全性。
|
|
|
|
|
|
|
|
|
|
|
|
那么当有一个 `Option<T>` 的值时,如何从 `Some` 成员中取出 `T` 的值来使用它呢?`Option<T>` 枚举拥有大量用于各种情况的方法:你可以查看[它的文档](https://doc.rust-lang.org/std/option/enum.Option.html)。熟悉 `Option<T>` 的方法将对你的 Rust 之旅非常有用。
|
|
|
|
那么当有一个 `Option<T>` 的值时,如何从 `Some` 成员中取出 `T` 的值来使用它呢?`Option<T>` 枚举拥有大量用于各种情况的方法:你可以查看[它的文档](https://doc.rust-lang.org/std/option/enum.Option.html)。熟悉 `Option<T>` 的方法将对你的 Rust 之旅非常有用。
|
|
|
|
|
|
|
|
|
|
|
|