Refining Ch06.

This commit is contained in:
rust-lang.xfoss.com 2023-12-18 13:17:33 +08:00
parent f80e61a96f
commit 55746ebe6a
3 changed files with 45 additions and 20 deletions

View File

@ -0,0 +1,8 @@
[package]
name = "option_demo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,6 @@
fn main() {
let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = x + y;
}

View File

@ -236,20 +236,23 @@ enum 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` 来保存数字与字符串类型的一些示例:
`<T>` 这种语法,是我们尚未讨论过的一项 Rust 特性。他是个泛型参数,我们将在第 10 章,详细介绍泛型。现在,咱们只需知道 `<T>` 表示 `Option` 枚举的 `Some` 变种,可以容纳任意类型的数据,而每个用来代替 `T` 的具体类型,都会使整个 `Option<T>` 类型,成为不同的类型。下面是一些使用 `Option` 值,保存数字类型和字符串类型的示例:
```rust
let some_numer = Some(5);
let some_string = Some("一个字符串");
let some_char = Some('e');
let absent_number: Option<i32> = None;
```
`some_number` 的类型为 `Option<i32>`。`some_string` 的类型为 `Option<&str>`,是个不同的类型。由于这里已在 `Some` 变种里面指定了值,因此 Rust 可推导出这些类型来。而对于 `absent_number`Rust 就要求注释整个 `Option` 类型:编译器无法通过仅查看一个 `None` 值,而推导出相应的 `Some` 变种的类型来。这里告诉了 Rust这里计划的是 `absent_number` 为类型 `Option<i32>`
在有着一个 `Some` 值时,就知道存在着一个值,且该值是保存在 `Some` 内部的。而在有个 `None` 值时,某种意义上讲,这表示了与空值同样的情况:没有一个有效值。那么究竟为什么有着 `Option<T>` 就是要比有着空值 `null` 好呢?
其中 `some_number` 的类型是 `Option<i32>`。`some_char` 的类型是 `Option<char>`这是一种不同的类型。Rust 可以推断出这些类型,因为我们在 `Some` 变种中,指定了某个值。对于 `absent_number`Rust 要求我们注解整个 `Option` 类型:编译器无法仅通过查看 `None` 值,来推断相应 `Some` 变种将持有的类型。在这里,我们告诉 Rust我们的意思是 `absent_number` 属于 `Option<i32>` 类型。
当我们有某个 `Some` 值时,我们知道有个值存在,并且该值被保存在 `Some` 中。当我们有个 `None` 值时,从某种意义上说,他的含义与空值相同:我们没有一个有效值。那么,为什么 `Option<T>` 比空值更好呢?
简而言之,由于 `Option<T>``T``T` 可以是任何类型)属于不同的类型,编译器不会让我们,将某个 `Option<T>` 值用作其肯定是个有效值。例如,下面这段代码将不会编译,因为他试图将一个 `i8`,与一个 `Option<i8>` 相加:
简而言之,由于 `Option<T>``T` (其中的 `T` 可以是任意类型) 为不同类型,因此编译器就不会允许将一个 `Option<T>` 值,当作一个必然的有效值来使用。比如,由于下面这段代码是在尝试将一个 `i8` 值,添加到某个 `Option<i8>` 上,因此这段代码不会编译:
```rust
let x: i8 = 5;
@ -258,29 +261,37 @@ enum Option<T> {
let sum = x + y;
```
在运行这段代码时,就会得到下面这样的错误消息:
如果我们运行这段代码,我们会收到如下报错:
```console
$ cargo run  ✔
Compiling enum_demo v0.1.0 (/home/peng/rust-lang/projects/enum_demo)
$ cargo run
Compiling option_demo v0.1.0 (C:\tools\msys64\home\Lenny.Peng\rust-lang-zh_CN\projects\option_demo)
error[E0277]: cannot add `Option<i8>` to `i8`
--> src/main.rs:24:17
--> src\main.rs:5:17
|
24 | let sum = x + y;
5 | let sum = x + y;
| ^ no implementation for `i8 + Option<i8>`
|
= help: the trait `Add<Option<i8>>` is not implemented for `i8`
= help: the following other types implement trait `Add<Rhs>`:
<i8 as Add>
<i8 as Add<&i8>>
<&'a i8 as Add<i8>>
<&i8 as Add<&i8>>
For more information about this error, try `rustc --explain E0277`.
error: could not compile `enum_demo` due to previous error
error: could not compile `option_demo` (bin "option_demo") due to previous error
```
强悍!事实上,这个错误消息表示,由于 `i8``Option<i8>` 属于不同类型,因此 Rust 不知道怎样将一个 `i8` 值与一个 `Option<i8>` 值相加。当在 Rust 中有着一个类型好比 `i8` 这样的值时,编译器就会保证始终有个有效值。在对那个值进行使用前,可不必检查他是不是 `null`,而可放心地加以处理。仅当有个 `Option<i8>` 类型(或其他任何正在使用的`Option<T>` 枚举类型值)的变量时,才真地必须关心可能并无值,同时编译器将确保在使用该值前,显式地处理无值的情况。
也就是说,在对 `Option<T` 执行类型参数 `T` 的那些操作前,必须将 `Option<T>` 类型转换为 `T` 类型。通常,这样做有助于捕获到 `null` 最常见问题之一:在某个东西实际上是 `null` 时,错误地将其设想为了他不是 `null`
强悍如此!实际上,这条报错信息,表示 Rust 不理解如何将某个 `i8` 与某个 `Option<i8>` 相加,因为他们属于不同的类型。在 Rust 中,当我们有个 `i8` 类型的值时,编译器会确保我们,始终有个有效的值。在使用该值之前,我们无需检查是否为空值,就可以放心地继续。只有当我们有个 `Option<i8>`(或其他任何类型的值)时,我们才必须担心可能并没有值,编译器会确保我们,在使用该值前处理这种情况
这种消除了不正确的假定某个非 `null` 值的做法,有助于增强代码自信。为了使用一个可能为 `null` 的值,就必须显式地通过将那个值的构造为 `Option<T>`,来带入这个值。在某个类型不为 `Option<T>` 值出现的每个地方,就都可以假定该值不是 `null`。这是 Rust 有意的设计决定,用以限制 `null` 的无处不在,及提升 Rust 代码的安全性
换句话说,在对 `Option<T>` 执行 `T` 的运算之前,我们必须先将其转换为 `T`。一般来说,这有助于捕捉空值最常见的问题之一:假设了某个项目不是空值,而实际上他却是空值
那么在有一个类型为 `Option<T>` 值的时候,该怎么从 `Some` 变种获取到 `T` 这个值,从而就可以用上那个值呢?枚举 `Option<T>` 有着大量的、在不同情形下有用的方法;在 [`Option<T>` 文档](https://doc.rust-lang.org/std/option/enum.Option.html) 便可查看到这些方法。熟悉 `Option<T>` 上的这些方法,将对 Rust 编程生涯极为有用
消除错误地假定某个非空值的风险,可以让咱们对咱们代码更有信心。为了获得某个可能为空的值,咱们必须显式地选择,将该值的类型设为 `Option<T>`。然后,在使用该值时,咱们必须显式地处理,该值为空的情况。只要值的类型不是 `Option<T>`,咱们就可以放心地认为,该值不是空值。这是 Rust 为限制空值泛滥,和提高 Rust 代码的安全性,而特意做出的设计决定
总的来说,为了使用某个 `Option<T>` 值,就要有将会处理各个变种的代码。要有一些只会在有着一个 `Some<T>` 的值时运行的代码,而此情况下就会允许这代码使用那个内部的 `T` 类型变量。在有着 `None` 值时,则还要有别的代码来允许了,而这代码就没有可用的 `T` 类型值了。在与枚举一起使用的时候,`match` 表达式正是实现此特性的控制流结构:`match` 表达式将依据枚举有着哪些变种,而运行相应的不同代码,以及哪些代码可使用匹配值内部的数据。
那么,当咱们有着某个 `Option<T>` 类型的值时,该怎样从 `Some` 变种中获取到那个 `T` 值,以便使用该值呢?`Option<T>` 这个枚举,有着大量在不同场景下,都有用的方法;咱们可以在 [其文档](https://doc.rust-lang.org/std/option/enum.Option.html) 中,查看这些方法。熟悉 `Option<T>` 的方法,将对咱们的 Rust 之旅大有裨益。
一般来说,为了使用某个 `Option<T>` 值,咱们需要编写处理每个变种的代码。咱们会想要一些,仅在咱们有个 `Some(T)` 值时才会运行的代码,而这些代码,就可以使用内部的 `T` 值;咱们会想要另一些,只有在咱们有个 `None` 值时才会运行的代码,而这些代码就没有可用的 `T` 值。与枚举一起使用的 `match` 表达式,便是一种正好完成这个目的的控制流结构:他会根据枚举有着哪一个变种,而运行不同的代码,而这些代码,就可以使用匹配值内部的数据。