mirror of
https://github.com/gnu4cn/rust-lang-zh_CN.git
synced 2025-03-14 03:10:44 +08:00
Refining Ch06.
This commit is contained in:
parent
138c582ccb
commit
f80e61a96f
@ -179,53 +179,52 @@ struct ChangeColorMessage(i32, i32, i32); // 元组结构体
|
||||
```
|
||||
|
||||
|
||||
但是,如果我们使用不同结构体(每个结构体都有自己的类型),我们就无法像使用清单 6-2 中定义的 `Message` 枚举(这是一种单一类型)那样,轻松定义出取任何一种这些类别消息。
|
||||
但是,如果我们使用不同结构体(每个结构体都有自己的类型),我们就无法像使用清单 6-2 中定义的 `Message` 枚举(是个单一类型)那样,轻松定义出取任何一种这些类别消息的函数。
|
||||
|
||||
枚举和结构体之间,还有个相似之处:正如我们可以使用 `impl` 在结构体上定义方法一样,我们也可以在枚举上定义方法。下面是我们可以在 `Message` 枚举上,定义的一个名为 `call` 的方法:
|
||||
|
||||
枚举与结构体之间,还有另外一个相似点:正如在结构体上使用 `impl` 关键字定义出一些方法,在枚举上定义方法也是可以的。下面就是一个可定义在这里的 `Message` 枚举上、名为 `call` 的方法:
|
||||
|
||||
```rust
|
||||
enum Message {
|
||||
Quit,
|
||||
Move { x: i32, y: i32 },
|
||||
Write (String),
|
||||
ChangeColor(i32, i32, i32),
|
||||
}
|
||||
|
||||
impl Message {
|
||||
fn call(&self) {
|
||||
// 方法体将定义在这里
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
let m = Message::Write(String::from("hello"));
|
||||
m.call();
|
||||
}
|
||||
```
|
||||
|
||||
方法体将使用 `self`,来获取方法调用所在变种实例值。在此示例中,已创建了一个有着值 `Message::Write(String::from("hello"))` 的变量 `m`,而那就是在 `m.call()` 运行时,`call` 方法体中的那个 `self`。
|
||||
|
||||
下面就来看看标准库中另一个甚为常见和有用的枚举:`Option`。
|
||||
这个方法的主体,将使用 `self` 来获取我们在其上调用该方法的值。在本例中,我们创建了一个值为 `Message::Write(String::from("hello"))` 的变量 `m`,当 `m.call()` 运行时,这就是出现在 `call` 方法主体中 `self` 的内容。
|
||||
|
||||
我们来看看标准库中,另一个非常常见和有用的枚举:`Option`。
|
||||
|
||||
|
||||
## 枚举 `Option` 及其超越空值的诸多优点
|
||||
## `Option` 枚举及其相对于空值的优势
|
||||
|
||||
**The `Option` Enum and Its Advantages Over Null Values**
|
||||
|
||||
本小节会探讨 `Option` 的案例研究,`Option` 是由标准库定义的另一个枚举。`Option` 类型编码了某个值可能会是某个物件,或可能什么都不属于的这种甚为常见的场景(the `Option` type encodes the very common scenario in which a value could be something or it could be nothing)。比如在请求某个含有一些项目的清单的第一个项目时,就会得到一个值。而在请求某个空清单的第一个项目时,则会什么也得不到。以类型系统字眼,来表达这个概念,就表示编译器能够对,是否已处理了本应处理的全部情形,进行检查;此项功能可阻止那些在其他编程语言中极为常见的代码错误。
|
||||
|
||||
编程语言的设计,通常要考量包含哪些特性,而要排除哪些特性也至关重要。Rust 没有许多其他语言都有的空值特性。*空值(Null)* 是一个表示此处无值的值。在带有 `null` 的那些语言中,变量总是会处于下面两个状态之一:空值或非空值。
|
||||
本节会探讨 `Option` 的一个案例研究,这是标准库定义的另一枚举。`Option` 类型编码了一种非常常见的情况,即某个值可能是某物,也可能什么都不是。
|
||||
|
||||
在 `null` 的发明人Tony Hoare 于 2009 年的演讲 “空值引用:10 亿美金代价失误(Null Reference: The Billion Dollar Mistake)” 中,就讲了这个问题:
|
||||
例如,如果咱们请求了某个非空列表中的首个项目,咱们将得到某个值。如果咱们请求某个空列表中的第一项,则什么也得不到。用类型系统来表达这一概念,意味着编译器可以检查,咱们是否处理了所有应处理的情况;这一功能可以防止其他编程语言中,极为常见的编程错误。
|
||||
|
||||
> 我把他叫做我的 10 亿美元失误。那个时候我正在设计某门面向对象语言中的首个综合类型系统。目的是要在编译器自动执行的检查之下,确保全部引用使用,都应绝对安全。仅仅因为空值引用变量实现起来很容易,我当时就没能顶住诱惑,把他加入到特性集了。这个举动,业已造成了数不胜数的代码错误、漏洞及系统崩溃等等问题,在过去 40 余年里,这些问题可能已经造成大概 10 亿美金的痛苦和伤害。
|
||||
编程语言的设计,通常会考虑包含哪些功能,但排除哪些功能,也很重要。Rust 没有许多其他语言所具有的空值 null 功能。*Null* 是个表示没有值的值。在有控制的语言中,变量总是处于两种状态之一:空值或非空值。
|
||||
|
||||
`null` 值的问题在于,当尝试将 `null` 值用作非 `null` 值时,就会得到某种错误。由于这种 `null` 或非 `null` 的属性遍布各处,因此极容易犯下此类错误。
|
||||
空值的发明者 Tony Hoare 于 2009 年的演讲 “空值引用:10 亿美金代价失误(Null Reference: The Billion Dollar Mistake)” 中,就讲了这个问题:
|
||||
|
||||
但 `null` 试图表达的概念,还是有用的:`null` 是个因某些原因,而当前为无效或空缺的值。
|
||||
|
||||
问题不是真的在于这个概念,而在于针对性的实现。由于这些原因,Rust 就没有空值,但他确实有一个可对值存在或空缺这个概念,进行编码的枚举。这个枚举就是 `Option<T>`,而这个枚举 [由标准库定义](https://doc.rust-lang.org/std/option/enum.Option.html) 为下面这样:
|
||||
> 我称他为我的 "十亿美元错误"。当时,我正在为面向对象语言中的引用,设计第一个全面的类型系统。我的目标是确保所有引用的使用,都绝对安全,并由编译器自动进行检查。但是,我无法抵制加入空引用的诱惑,只是因为这太容易实现了。这导致了无数的错误、漏洞和系统崩溃,在过去的四十年里,这些错误和漏洞可能造成了数十亿美元的损失。
|
||||
|
||||
|
||||
空值的问题在于,如果试图将空值用作非空值,就会出现某种错误。由于这种空值或非空值属性普遍存在,因此极易出现这种错误。
|
||||
|
||||
然而,空值试图表达的这种概念,仍然是有用的:空值是指由于某种原因,当前无效或不存在的值。
|
||||
|
||||
问题其实不在于概念,而在于特定的实现。因此,Rust 没有空值,但有个枚举可以编码值存在或不存在的概念。这个枚举就是 `Option<T>`,[标准库对其定义](https://doc.rust-lang.org/std/option/enum.Option.html) 如下:
|
||||
|
||||
|
||||
```rust
|
||||
enum Option<T> {
|
||||
@ -234,7 +233,8 @@ enum Option<T> {
|
||||
}
|
||||
```
|
||||
|
||||
这个 `Option<T>` 是如此重要,以至于在 Rust 序曲(the prelude)中甚至都包含了;是不需要显式地将其带入到作用域的(注:*原生类型、这里的 `Option<T>`,以及前面的 `String` 类型等等,就是这样的包含在序曲中的类型,无需显式地带入到作用域,就可以直接使用*)。该枚举的变种也已包含在 Rust 序曲中:可直接在不带前缀 `Option::` 的情况下直接使用 `Some` 与 `None`(注:*那么 `Some` 与 `None` 就被列为了 Rust 关键字了*)。`Option<T>` 仍然只是常规枚举,而 `Some<T>` 与 `None` 仍然是类型 `Option<T>` 的变种。
|
||||
|
||||
`Option<T>` 枚举非常有用,以致他甚至被包含在 Rust 前奏中;咱们不需要显式地将他引入作用域。他的变种也包含在前奏中:咱们可以直接使用 `Some` 和 `None`,而无需 `Option::` 这个前缀。`Option<T>` 枚举仍然只是个普通的枚举,而 `Some(T)` 和 `None`,也仍然是 `Option<T>` 类型的变种。
|
||||
|
||||
这里的 `<T>` 语法,是个到目前为止还未讲到的 Rust 特性。他是个泛型参数,而在第 10 章将更详细的涉及到泛型。至于现在,只需明白 `<T>` 表示 `Option` 枚举的 `Some` 变种,可保存任意类型的一条数据,而在 `T` 位置处用到的各个具体类型,会让整个 `Option<T>` 类型成为各异的类型(for now, all you need to know is that `<T>` means the `Some` variant of the `Option` enum can hold one piece of data of any type, and that each concrete type that gets used in place of `T` makes the overall `Option<T>` type a different type)。以下是使用 `Option` 来保存数字与字符串类型的一些示例:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user