update ch06-01

main
KaiserY 3 days ago
parent 9bf7ebf815
commit eae61e2b3a

@ -1,8 +1,7 @@
# 使用结构体组织相关联的数据 # 使用结构体组织相关联的数据
<!-- https://github.com/rust-lang/book/blob/main/src/ch05-00-structs.md --> [ch05-00-structs.md](https://github.com/rust-lang/book/blob/8a6130451b0817ead5c2522ce641dcb0f11a8571/src/ch05-00-structs.md)
<!-- commit 8a6130451b0817ead5c2522ce641dcb0f11a8571 -->
**结构体***struct*),或者 *structure*,是一个自定义数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,你会发现一个 struct 就像对象的数据属性。在本章中,我们会比较元组和结构体的异同,在你已有知识的基础上进一步探讨,并演示在何种情况下结构体是组合数据的更好方式。 **结构体***struct*),或者 *structure*,是一个自定义数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,你会发现一个 struct 就像对象的数据属性。在本章中,我们会比较元组和结构体的异同,在你已有知识的基础上进一步探讨,并演示在何种情况下结构体是组合数据的更好方式。
我们还将演示如何定义和实例化结构体,并讨论如何定义关联函数,特别是被称为 *方法* 的那种关联函数,以指定与结构体类型相关的行为。你可以在程序中基于结构体和枚举(*enum*)(在第六章介绍)创建新类型,以充分利用 Rust 的编译时类型检查。 我们还将演示如何定义和实例化结构体,并讨论如何定义关联函数,特别是被称为 *方法* 的那种关联函数,以指定与结构体类型相关的行为。结构体和枚举(*enum*,会在第六章介绍)是为你的程序领域创建新类型的基础构件,从而可以充分利用 Rust 的编译时类型检查。

@ -1,7 +1,6 @@
## 结构体的定义和实例化 ## 结构体的定义和实例化
<!-- https://github.com/rust-lang/book/blob/main/src/ch05-01-defining-structs.md --> [ch05-01-defining-structs.md](https://github.com/rust-lang/book/blob/8a6130451b0817ead5c2522ce641dcb0f11a8571/src/ch05-01-defining-structs.md)
<!-- commit e4681b573677380154825f383546b68e6111a725 -->
结构体和我们在[“元组类型”][tuples]部分讨论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。 结构体和我们在[“元组类型”][tuples]部分讨论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
@ -47,7 +46,7 @@
<span class="caption">示例 5-4`build_user` 函数获取 email 和用户名并返回 `User` 实例</span> <span class="caption">示例 5-4`build_user` 函数获取 email 和用户名并返回 `User` 实例</span>
为函数参数起与结构体字段相同的名字是可以理解的,但是不得不重复 `email``username` 字段名称与变量有些啰嗦。如果结构体有更多字段,重复每个名称就更加烦人了。幸运的是,有一个方便的简写语法! 为函数参数使用与结构体字段相同的名字是很合理的,但不得不重复写 `email``username` 这些字段名和变量名,多少有些啰嗦。如果结构体有更多字段,重复每个名称就更烦人了。幸运的是,有一种方便的简写语法!
### 使用字段初始化简写语法 ### 使用字段初始化简写语法
@ -63,7 +62,7 @@
这里我们创建了一个新的 `User` 结构体实例,它有一个叫做 `email` 的字段。我们想要将 `email` 字段的值设置为 `build_user` 函数 `email` 参数的值。因为 `email` 字段与 `email` 参数有着相同的名称,则只需编写 `email` 而不是 `email: email` 这里我们创建了一个新的 `User` 结构体实例,它有一个叫做 `email` 的字段。我们想要将 `email` 字段的值设置为 `build_user` 函数 `email` 参数的值。因为 `email` 字段与 `email` 参数有着相同的名称,则只需编写 `email` 而不是 `email: email`
### 使用结构体更新语法从其他实例创建实例 ### 使用结构体更新语法创建实例
使用旧实例的大部分值但改变其部分值来创建一个新的结构体实例通常是很有用的。这可以通过 **结构体更新语法***struct update syntax*)实现。 使用旧实例的大部分值但改变其部分值来创建一个新的结构体实例通常是很有用的。这可以通过 **结构体更新语法***struct update syntax*)实现。
@ -89,9 +88,9 @@
示例 5-7 中的代码也在 `user2` 中创建了一个新实例,但该实例中 `email` 字段的值与 `user1` 不同,而 `username``active``sign_in_count` 字段的值与 `user1` 相同。`..user1` 必须放在最后,以指定其余的字段应从 `user1` 的相应字段中获取其值,但我们可以选择以任何顺序为任意字段指定值,而不用考虑结构体定义中字段的顺序。 示例 5-7 中的代码也在 `user2` 中创建了一个新实例,但该实例中 `email` 字段的值与 `user1` 不同,而 `username``active``sign_in_count` 字段的值与 `user1` 相同。`..user1` 必须放在最后,以指定其余的字段应从 `user1` 的相应字段中获取其值,但我们可以选择以任何顺序为任意字段指定值,而不用考虑结构体定义中字段的顺序。
请注意,结构更新语法就像带有 `=` 的赋值,因为它移动了数据,就像我们在[“使用移动的变量与数据交互”][move]部分讲到的一样。在这个例子中,总体上说我们在创建 `user2` 后就不能再使用 `user1` 了,因为 `user1``username` 字段中的 `String` 被移到 `user2` 中。如果我们给 `user2``email``username` 都赋予新的 `String` 值,从而只复用 `user1``active``sign_in_count` 值,那么 `user1` 在创建 `user2` 后仍然有效。`active` 和 `sign_in_count` 的类型是实现 `Copy` trait 的类型,所以我们在[“使用克隆的变量与数据交互”][copy] 部分讨论的行为同样适用。在本例中我们也可以继续使用 `user1.email`,因为它的值并未从 `user1` 中移动出去。 请注意,结构更新语法就像带有 `=` 的赋值,因为它移动了数据,就像我们在[“使用移动的变量与数据交互”][move]部分讲到的一样。在这个例子中,总体上说我们在创建 `user2` 后就不能再使用 `user1` 了,因为 `user1``username` 字段中的 `String` 被移到 `user2` 中。如果我们给 `user2``email``username` 都赋予新的 `String` 值,从而只复用 `user1``active``sign_in_count` 值,那么 `user1` 在创建 `user2` 后仍然有效。`active` 和 `sign_in_count` 的类型是实现 `Copy` trait 的类型,所以我们在[“只在栈上的数据:拷贝”][copy] 部分讨论的行为同样适用。在本例中我们也可以继续使用 `user1.email`,因为它的值并未从 `user1` 中移动出去。
### 使用没有命名字段的元组结构体创建不同的类型 ### 使用元组结构体创建不同的类型
也可以定义与元组类似的结构体,称为 **元组结构体***tuple structs*)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。 也可以定义与元组类似的结构体,称为 **元组结构体***tuple structs*)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。
@ -105,9 +104,9 @@
注意 `black``origin` 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段可能有着相同的类型。例如,一个获取 `Color` 类型参数的函数不能接受 `Point` 作为参数,即便这两个类型都由三个 `i32` 值组成。除此之外,元组结构体实例类似于元组,你可以将它们解构为单独的部分,也可以使用 `.` 后跟索引来访问单独的值。与元组不同的是,解构元组结构体时必须写明结构体的类型。例如,我们可以写 `let Point(x, y, z) = origin;`,将 `origin` 的值解构到名为 `x`、`y` 和 `z` 的变量中。 注意 `black``origin` 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段可能有着相同的类型。例如,一个获取 `Color` 类型参数的函数不能接受 `Point` 作为参数,即便这两个类型都由三个 `i32` 值组成。除此之外,元组结构体实例类似于元组,你可以将它们解构为单独的部分,也可以使用 `.` 后跟索引来访问单独的值。与元组不同的是,解构元组结构体时必须写明结构体的类型。例如,我们可以写 `let Point(x, y, z) = origin;`,将 `origin` 的值解构到名为 `x`、`y` 和 `z` 的变量中。
### 没有任何字段的类单元结构体 ### 定义类单元结构体
我们也可以定义一个没有任何字段的结构体!它们被称为 **类单元结构体***unit-like structs*因为它们类似于 `()`,即[“元组类型”][tuples]一节中提到的 unit 类型。类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。我们将在第十章介绍 trait。下面是一个声明和实例化一个名为 `AlwaysEqual` 的 unit 结构的示例 你也可以定义没有任何字段的结构体!它们被称为 **类单元结构体***unit-like structs*,因为它们的行为类似于 `()`,也就是我们在[“元组类型”][tuples]一节中提到的 unit 类型。类单元结构体在你想要在某个类型上实现 trait但又不需要在该类型本身中存储任何数据时会很有用。我们会在第十章讨论 trait。下面是一个声明和实例化名为 `AlwaysEqual` 的 unit 结构体的例子
<span class="filename">文件名src/main.rs</span> <span class="filename">文件名src/main.rs</span>
@ -179,8 +178,8 @@
> error: could not compile `structs` (bin "structs") due to 2 previous errors > error: could not compile `structs` (bin "structs") due to 2 previous errors
> ``` > ```
> >
> 第十章会讲到如何修复这个问题以便在结构体中存储引用,不过现在,我们会使用像 `String` 这类拥有所有权的类型来替代 `&str` 这样的引用以修正这个错误。 > 第十章会讨论如何修复这些错误,从而让你可以在结构体中存储引用;不过现在,我们会用像 `String` 这样的拥有所有权的类型来替代像 `&str` 这样的引用,以此修复这类错误。
[tuples]: ch03-02-data-types.html#元组类型 [tuples]: ch03-02-data-types.html#元组类型
[move]: ch04-01-what-is-ownership.html#使用移动的变量与数据交互 [move]: ch04-01-what-is-ownership.html#使用移动的变量与数据交互
[copy]: ch04-01-what-is-ownership.html#使用克隆的变量与数据交互 [copy]: ch04-01-what-is-ownership.html#只在栈上的数据-拷贝

@ -1,7 +1,6 @@
## 结构体示例程序 ## 结构体示例程序
<!-- https://github.com/rust-lang/book/blob/main/src/ch05-02-example-structs.md --> [ch05-02-example-structs.md](https://github.com/rust-lang/book/blob/8a6130451b0817ead5c2522ce641dcb0f11a8571/src/ch05-02-example-structs.md)
<!-- commit 02e053cdbbb3bf9edd9ad32ed49eb533404350a9 -->
为了理解何时会需要使用结构体,让我们编写一个计算长方形面积的程序。我们会从单独的变量开始,接着重构程序直到使用结构体替代它们为止。 为了理解何时会需要使用结构体,让我们编写一个计算长方形面积的程序。我们会从单独的变量开始,接着重构程序直到使用结构体替代它们为止。
@ -47,7 +46,7 @@
在计算面积时将宽和高弄混倒无关紧要,不过当在屏幕上绘制长方形时就有问题了!我们必须牢记 `width` 的元组索引是 `0``height` 的元组索引是 `1`。如果其他人要使用这些代码,他们必须要搞清楚这一点,并也要牢记于心。很容易忘记或者混淆这些值而造成错误,因为我们没有在代码中传达数据的意图。 在计算面积时将宽和高弄混倒无关紧要,不过当在屏幕上绘制长方形时就有问题了!我们必须牢记 `width` 的元组索引是 `0``height` 的元组索引是 `1`。如果其他人要使用这些代码,他们必须要搞清楚这一点,并也要牢记于心。很容易忘记或者混淆这些值而造成错误,因为我们没有在代码中传达数据的意图。
### 使用结构体重构:赋予更多意义 ### 使用结构体重构
我们使用结构体为数据命名来为其赋予意义。我们可以将我们正在使用的元组转换成一个有整体名称而且每个部分也有对应名字的结构体,如示例 5-10 所示: 我们使用结构体为数据命名来为其赋予意义。我们可以将我们正在使用的元组转换成一个有整体名称而且每个部分也有对应名字的结构体,如示例 5-10 所示:
@ -65,7 +64,7 @@
`area` 函数访问 `Rectangle` 实例的 `width``height` 字段(注意,访问对结构体的引用的字段不会移动字段的所有权,这就是为什么你经常看到对结构体的引用)。`area` 的函数签名现在明确的阐述了我们的意图:使用 `Rectangle``width``height` 字段,计算 `Rectangle` 的面积。这表明宽高是相互联系的,并为这些值提供了描述性的名称而不是使用元组的索引值 `0``1` 。这在可读性上是一个明显的提升。 `area` 函数访问 `Rectangle` 实例的 `width``height` 字段(注意,访问对结构体的引用的字段不会移动字段的所有权,这就是为什么你经常看到对结构体的引用)。`area` 的函数签名现在明确的阐述了我们的意图:使用 `Rectangle``width``height` 字段,计算 `Rectangle` 的面积。这表明宽高是相互联系的,并为这些值提供了描述性的名称而不是使用元组的索引值 `0``1` 。这在可读性上是一个明显的提升。
### 通过派生 trait 增加实用功能 ### 通过派生 trait 增加功能
在调试程序时打印出 `Rectangle` 实例来查看其所有字段的值非常有用。示例 5-11 像前面章节那样尝试使用 [`println!` 宏][println]。但这并不行。 在调试程序时打印出 `Rectangle` 实例来查看其所有字段的值非常有用。示例 5-11 像前面章节那样尝试使用 [`println!` 宏][println]。但这并不行。
@ -91,7 +90,7 @@
{{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt:9:10}} {{#include ../listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt:9:10}}
``` ```
让我们来试试!现在 `println!` 宏调用看起来`println!("rect1 is {:?}", rect1);` 这样。在 `{}` 中加入 `:?` 指示符告诉 `println!` 我们想要使用叫做 `Debug` 的输出格式。`Debug` 是一个 trait它允许我们以一种对开发者有帮助的方式打印结构体以便当我们调试代码时能看到它的值。 让我们来试试!现在 `println!` 宏调用看起来会像 `println!("rect1 is {rect1:?}");`。在大括号中加入 `:?` 指示符,告诉 `println!` 我们想使用一种叫做 `Debug` 的输出格式。`Debug` 是一个 trait它允许我们以一种对开发者有帮助的方式打印结构体这样在调试代码时就能看到它的值。
这样调整后再次运行程序。见鬼了!仍然能看到一个错误: 这样调整后再次运行程序。见鬼了!仍然能看到一个错误:

@ -1,11 +1,10 @@
## 方法 ## 方法
<!-- https://github.com/rust-lang/book/blob/main/src/ch05-03-method-syntax.md --> [ch05-03-method-syntax.md](https://github.com/rust-lang/book/blob/8a6130451b0817ead5c2522ce641dcb0f11a8571/src/ch05-03-method-syntax.md)
<!-- commit 6b65e9500535f85fad186c6f0e67a927863e454d -->
**方法**method与函数类似它们使用 `fn` 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义(或者是枚举或 trait 对象的上下文,将分别在[第六章][enums]和[第十八章][trait-objects]讲解),并且它们第一个参数总是 `self`,它代表调用该方法的结构体实例。 **方法**method与函数类似它们使用 `fn` 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义(或者是枚举或 trait 对象的上下文,将分别在[第六章][enums]和[第十八章][trait-objects]讲解),并且它们第一个参数总是 `self`,它代表调用该方法的结构体实例。
### 定义方法 ### 方法语法
让我们把前面实现的获取一个 `Rectangle` 实例作为参数的 `area` 函数,改写成一个定义于 `Rectangle` 结构体上的 `area` 方法,如示例 5-13 所示: 让我们把前面实现的获取一个 `Rectangle` 实例作为参数的 `area` 函数,改写成一个定义于 `Rectangle` 结构体上的 `area` 方法,如示例 5-13 所示:
@ -25,7 +24,7 @@
使用方法替代函数,除了可使用方法语法和不需要在每个函数签名中重复 `self` 的类型之外,其主要好处在于组织性。我们将某个类型实例能做的所有事情都一起放入 `impl` 块中,而不是让将来的用户在我们的库中到处寻找 `Rectangle` 的功能。 使用方法替代函数,除了可使用方法语法和不需要在每个函数签名中重复 `self` 的类型之外,其主要好处在于组织性。我们将某个类型实例能做的所有事情都一起放入 `impl` 块中,而不是让将来的用户在我们的库中到处寻找 `Rectangle` 的功能。
请注意,我们可以选择将方法的名称与结构中的一个字段相同。例如,我们可以在 `Rectangle` 上定义一个方法,并命名为 `width` 请注意,我们可以选择让方法与结构体中的某个字段同名。例如,我们可以在 `Rectangle` 上定义一个也叫做 `width` 的方法
<span class="filename">文件名src/main.rs</span> <span class="filename">文件名src/main.rs</span>
@ -35,7 +34,7 @@
在这里,我们选择让 `width` 方法在实例的 `width` 字段的值大于 `0` 时返回 `true`,等于 `0` 时则返回 `false`:我们可以出于任何目的,在同名的方法中使用同名的字段。在 `main` 中,当我们在 `rect1.width` 后面加上括号时。Rust 知道我们指的是方法 `width`。当我们不使用圆括号时Rust 知道我们指的是字段 `width` 在这里,我们选择让 `width` 方法在实例的 `width` 字段的值大于 `0` 时返回 `true`,等于 `0` 时则返回 `false`:我们可以出于任何目的,在同名的方法中使用同名的字段。在 `main` 中,当我们在 `rect1.width` 后面加上括号时。Rust 知道我们指的是方法 `width`。当我们不使用圆括号时Rust 知道我们指的是字段 `width`
通常,但并不总是如此,与字段同名的方法将被定义为只返回字段中的值,而不做其他事情。这样的方法被称为 *getters*Rust 并不像其他一些语言那样为结构字段自动实现它们。Getters 很有用,因为你可以把字段变成私有的,但方法是公共的,这样就可以把对字段的只读访问作为该类型公共 API 的一部分。我们将在[第七章][public]中讨论什么是公有和私有,以及如何将一个字段或方法指定为公有或私有。 通常情况下,虽然并不总是如此,与字段同名的方法会被定义为只返回该字段中的值,而不做其他事情。这样的方法被称为 *getters*。Rust 不会像其他一些语言那样为结构体字段自动生成 getter。Getter 很有用,因为你可以把字段设为私有,而把方法设为公有,从而将对该字段的只读访问作为该类型公有 API 的一部分。我们会在[第七章][public]讨论什么是公有和私有,以及如何把字段或方法指定为公有或私有。
> ### `->` 运算符到哪去了? > ### `->` 运算符到哪去了?
> >
@ -66,7 +65,7 @@
> (&p1).distance(&p2); > (&p1).distance(&p2);
> ``` > ```
> >
> 第一行看起来简洁的多。这种自动引用的行为之所以有效,是因为方法有一个明确的接收者———— `self` 的类型。在给出接收者和方法名的前提下Rust 可以明确地计算出方法是仅仅读取(`&self`),做出修改(`&mut self`)或者是获取所有权(`self`。事实上Rust 对方法接收者的隐式借用让所有权在实践中更友好 > 第一种写法看起来简洁得多。这种自动引用之所以成立,是因为方法有一个明确的接收者,也就是 `self` 的类型。给定接收者和方法名Rust 就能明确推断出该方法是只读(`&self`)、可变借用(`&mut self`)还是获取所有权(`self`。事实上Rust 对方法接收者的这种隐式借用,是所有权机制在实践中更易用的重要原因之一
### 带有更多参数的方法 ### 带有更多参数的方法

@ -1,6 +1,5 @@
# 枚举和模式匹配 # 枚举和模式匹配
<!-- https://github.com/rust-lang/book/blob/main/src/ch06-00-enums.md --> [ch06-00-enums.md](https://github.com/rust-lang/book/blob/602a0d2e898f5e4ff030eac0b457755a10e0be1e/src/ch06-00-enums.md)
<!-- commit 3a30e4c1fbe641afc066b3af9eb01dcdf5ed8b24 -->
本章介绍**枚举***enumerations*),也被称作 *enums*。枚举允许你通过列举可能的 **变体***variants*)来定义一个类型。首先,我们会定义并使用一个枚举来展示它是如何连同数据一起编码信息的。接下来,我们会探索一个特别有用的枚举,叫做 `Option`,它代表一个值要么是某个值要么什么都不是。然后会讲到在 `match` 表达式中用模式匹配,针对不同的枚举值编写相应要执行的代码。最后会介绍 `if let`,另一个简洁方便处理代码中枚举的结构 本章我们会介绍**枚举***enumerations*),也叫作 *enums*。枚举让你可以通过列举某个类型所有可能的 **变体***variants*)来定义这个类型。首先,我们会定义并使用一个枚举,展示它如何把含义和数据一起编码进去。接着,我们会探索一个特别有用的枚举 `Option`,它表达的是一个值要么是某个值,要么什么都不是。然后,我们会看到 `match` 表达式中的模式匹配如何让我们针对枚举的不同值运行不同的代码。最后,我们会介绍 `if let`,这是在代码中处理枚举时另一种简洁方便的惯用写法

@ -1,7 +1,6 @@
## 枚举的定义 ## 枚举的定义
<!-- https://github.com/rust-lang/book/blob/main/src/ch06-01-defining-an-enum.md --> [ch06-01-defining-an-enum.md](https://github.com/rust-lang/book/blob/602a0d2e898f5e4ff030eac0b457755a10e0be1e/src/ch06-01-defining-an-enum.md)
<!-- commit 2a4c00c4d0c373ff9b416712b74ffb7ed56c77d4 -->
结构体给予你将字段和数据聚合在一起的方法,像 `Rectangle` 结构体有 `width``height` 两个字段。而枚举给予你一个途径去声明某个值是一个集合中的一员。比如,我们想让 `Rectangle` 是一些形状的集合,包含 `Circle``Triangle` 。为此Rust 允许我们将这些可能性编码为一个枚举类型。 结构体给予你将字段和数据聚合在一起的方法,像 `Rectangle` 结构体有 `width``height` 两个字段。而枚举给予你一个途径去声明某个值是一个集合中的一员。比如,我们想让 `Rectangle` 是一些形状的集合,包含 `Circle``Triangle` 。为此Rust 允许我们将这些可能性编码为一个枚举类型。
@ -115,7 +114,7 @@ enum IpAddr {
让我们看看标准库中的另一个非常常见且实用的枚举:`Option`。 让我们看看标准库中的另一个非常常见且实用的枚举:`Option`。
### `Option` 枚举及其相对于空值的优势 ### `Option` 枚举
这一部分会分析一个 `Option` 的案例,`Option` 是标准库定义的另一个枚举。`Option` 类型应用广泛因为它编码了一个非常普遍的场景,即一个值要么有值要么没值。 这一部分会分析一个 `Option` 的案例,`Option` 是标准库定义的另一个枚举。`Option` 类型应用广泛因为它编码了一个非常普遍的场景,即一个值要么有值要么没值。
@ -161,7 +160,7 @@ enum Option<T> {
当有一个 `Some` 值时,我们就知道存在一个值,而这个值保存在 `Some` 中。当有个 `None` 值时,在某种意义上,它跟空值具有相同的意义:并没有一个有效的值。那么,`Option<T>` 为什么就比空值要好呢? 当有一个 `Some` 值时,我们就知道存在一个值,而这个值保存在 `Some` 中。当有个 `None` 值时,在某种意义上,它跟空值具有相同的意义:并没有一个有效的值。那么,`Option<T>` 为什么就比空值要好呢?
简而言之,因为 `Option<T>``T`(这里 `T` 可以是任何类型)是不同的类型,编译器不允许像一个肯定有效的值那样使用 `Option<T>`。例如,这段代码不能编译,因为它尝试将 `Option<i8>` `i8` 相加: 简而言之,因为 `Option<T>``T`(这里 `T` 可以是任何类型)是不同的类型,所以编译器不允许我们把 `Option<T>` 当成一个肯定有效的值来使用。例如,这段代码不能编译,因为它试图把 `Option<i8>` `i8` 相加:
```rust,ignore,does_not_compile ```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/src/main.rs:here}} {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/src/main.rs:here}}
@ -173,7 +172,7 @@ enum Option<T> {
{{#include ../listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt}} {{#include ../listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt}}
``` ```
很好!事实上,错误信息意味着 Rust 不知道该如何将 `Option<i8>``i8` 相加,因为它们的类型不同。当在 Rust 中拥有一个像 `i8` 这样类型的值时,编译器确保它总是有一个有效的值。我们可以自信地使用而无需做空值检查。只有当使用 `Option<i8>`(或者任何用到的类型)的时候需要担心可能没有值,而编译器会确保我们在使用值之前处理了为空的情况。 很好!事实上,这条错误信息的意思是Rust 不知道该如何把 `Option<i8>``i8` 相加,因为它们是不同的类型。当我们在 Rust 中拥有一个像 `i8` 这样的值时,编译器会确保它总是有效的。我们可以放心使用它,而无需先做空值检查。只有当我们使用 `Option<i8>`(或者任何别的 `Option<T>`)时,才需要考虑值可能不存在,而编译器会确保我们在使用这个值之前处理了这种情况。
换句话说,在对 `Option<T>` 进行运算之前必须将其转换为 `T`。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。 换句话说,在对 `Option<T>` 进行运算之前必须将其转换为 `T`。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。

Loading…
Cancel
Save