Merge pull request #174 from JesseAtSZ/patch-5

Update enum.md
pull/181/head
Sunface 3 years ago committed by GitHub
commit 7925cda437
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
# 枚举
枚举(enum或enumeration)允许你通过列举可能的成员来定义一个**枚举类型**,例如扑克牌花色:
枚举(enum或enumeration)允许你通过列举可能的成员来定义一个**枚举类型**例如扑克牌花色:
```rust
enum PokerSuit {
Clubs,
@ -14,7 +14,7 @@ enum PokerSuit {
再回到之前创建的`PokerSuit`,扑克总共有四种花色,而这里我们枚举出所有的可能值,这也正是`枚举`名称的由来。
任何一张扑克,它的花色肯定会落在四种花色中,而且也只会落在其中一个花色上,这种特性非常适合枚举的使用,因为**枚举值**只可能是其中一个成员。抽象来看,四种花色尽管是不同的花色,但是它们都是扑克花色这个概念,因此当某个函数处理扑克花色时,可以把它们当作相同的类型进行传参。
任何一张扑克,它的花色肯定会落在四种花色中,而且也只会落在其中一个花色上,这种特性非常适合枚举的使用,因为**枚举值**只可能是其中一个成员。抽象来看,四种花色尽管是不同的花色,但是它们都是扑克花色这个概念,因此当某个函数处理扑克花色时,可以把它们当作相同的类型进行传参。
细心的读者应该注意到,我们对之前的`枚举类型`和`枚举值`进行了重点标注,这是因为对于新人来说容易混淆相应的概念,总而言之:
**枚举类型是一个类型,它会包含所有可能的枚举成员, 而枚举值是该类型中的具体某个成员的实例。**
@ -43,7 +43,7 @@ fn print_suit(card: PokerSuit) {
`print_suit`函数的参数类型是`PokerSuit`,因此我们可以把`heart`和`diamond`传给它,虽然`heart`是基于`PokerSuit`下的`Hearts`成员实例化的,但是它是货真价实的`PokerSuit`枚举类型。
接下来,我们想扑克牌变得更加实用,那么需要给每张牌赋予一个值:`A`(1)-`K`(13)这样再加上花色就是一张真实的扑克牌了例如红心A。
接下来,我们想扑克牌变得更加实用,那么需要给每张牌赋予一个值:`A`(1)-`K`(13)这样再加上花色就是一张真实的扑克牌了例如红心A。
目前来说,枚举值还不能带有值,因此先用结构体来实现:
```rust
@ -70,9 +70,9 @@ fn main() {
};
}
```
这段代码很好的完成了它的使命,通过结构体`PokerCard`来代表一张牌,结构体的`suit`字段表示牌的花色,类型是`PokerSuit`枚举类型,`value`字段代表扑克牌的值。
这段代码很好的完成了它的使命,通过结构体`PokerCard`来代表一张牌,结构体的`suit`字段表示牌的花色,类型是`PokerSuit`枚举类型,`value`字段代表扑克牌的值。
可以吗?可以!好吗?说实话,不咋地,因为还有简洁多的方式来实现:
可以吗?可以!好吗?说实话,不咋地,因为还有简洁多的方式来实现:
```rust
enum PokerCard {
Clubs(u8),
@ -87,9 +87,9 @@ fn main() {
}
```
直接将数据信息关联到枚举成员上,直接省去近一半的代码,这种实现漂亮不
直接将数据信息关联到枚举成员上,省去近一半的代码,这种实现是不是更优雅
而且仅如此,同一个枚举类型下的不同成员还能持有不同的类型,例如让部分花色打印`1-13`的字样,另外花色打印上`A-K`的字样:
不仅如此,同一个枚举类型下的不同成员还能持有不同的数据类型,例如让某些花色打印`1-13`的字样,另外的花色打印上`A-K`的字样:
```rust
enum PokerCard {
Clubs(u8),
@ -122,7 +122,7 @@ enum IpAddr {
V6(Ipv6Addr),
}
```
例子跟我们之前的扑克牌很像,只不过枚举成员包含的类型更复杂了,变成了结构体:分别通过`Ipv4Addr`和`Ipv6Addr`来定义两种不同的IP数据。
这个例子跟我们之前的扑克牌很像,只不过枚举成员包含的类型更复杂了,变成了结构体:分别通过`Ipv4Addr`和`Ipv6Addr`来定义两种不同的IP数据。
从这些例子可以看出,**任何类型的数据都可以放入枚举成员中**: 例如字符串、数值、结构体甚至另一个枚举。
@ -209,7 +209,7 @@ enum Option<T> {
其中`T`是泛型参数,`Some(T)`表示该枚举成员的数据类型是`T`, 换句话说,`Some`可以包含任何类型的数据。
`Option<T>` 枚举是如此有用以至于它甚至被包含在了`prelude`(Rust会将最常用的类型、函数等提前引入进来,避免我们再手动引入)之中,你不需要将其显式引入作用域。另外,它的成员也是如此,无需使用`Option::`前缀就可直接使用`Some` 和 `None`。总之,不能因为`Some(T)`和`None`中没有`Option::`的身影,就否认它们是`Option`下的卧龙凤雏。
`Option<T>` 枚举是如此有用以至于它甚至被包含在了`prelude`(prelude属于Rust标准库Rust会将最常用的类型、函数等提前引入其中,避免我们再手动引入)之中,你不需要将其显式引入作用域。另外,它的成员`Some` 和 `None`也是如此,无需使用`Option::`前缀就可直接使用`Some` 和 `None`。总之,不能因为`Some(T)`和`None`中没有`Option::`的身影,就否认它们是`Option`下的卧龙凤雏。
再来看以下代码:
```rust
@ -245,9 +245,9 @@ not satisfied
|
```
很好!事实上,错误信息意味着 Rust 不知道该如何将 `Option<i8>``i8` 相加,因为它们的类型不同。当在 Rust 中拥有一个像 `i8` 这样类型的值时,编译器确保它总是有一个有效的值。我们可以自信使用而无需做空值检查。只有当使用 `Option<i8>`(或者任何用到的类型)的时候需要担心可能没有值,而编译器会确保我们在使用值之前处理了为空的情况。
很好!事实上,错误信息意味着 Rust 不知道该如何将 `Option<i8>``i8` 相加,因为它们的类型不同。当在 Rust 中拥有一个像 `i8` 这样类型的值时,编译器确保它总是有一个有效的值,我们可以放心使用而无需做空值检查。只有当使用 `Option<i8>`(或者任何用到的类型)的时候需要担心可能没有值,而编译器会确保我们在使用值之前处理了为空的情况。
换句话说,在对 `Option<T>` 进行 `T` 的运算之前必须将其转换为 `T`。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。
换句话说,在对 `Option<T>` 进行 `T` 的运算之前必须将其转换为 `T`。通常这能帮助我们捕获到空值最常见的问题之一:期望某值不为空但实际上为空的情况。
不再担心会错误的使用一个空值,会让你对代码更加有信心。为了拥有一个可能为空的值,你必须要显式的将其放入对应类型的 `Option<T>` 中。接着,当使用这个值时,必须明确的处理值为空的情况。只要一个值不是 `Option<T>` 类型,你就 **可以** 安全的认定它的值不为空。这是 Rust 的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加 Rust 代码的安全性。
@ -271,4 +271,4 @@ let six = plus_one(five);
let none = plus_one(None);
```
`plus_one`通过`match`来处理不同`Option`的情况。
`plus_one`通过`match`来处理不同`Option`的情况。

Loading…
Cancel
Save