Merge pull request #637 from Xuzheng77s/main

补丁#2
pull/641/head
KaiserY 3 years ago committed by GitHub
commit 0d39824be0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,8 +6,8 @@ struct Rectangle {
// ANCHOR: here
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}

@ -1,7 +1,7 @@
fn main() {
// ANCHOR: here
let some_number = Some(5);
let some_string = Some("a string");
let some_char = Some('e');
let absent_number: Option<i32> = None;
// ANCHOR_END: here

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

@ -2,7 +2,7 @@
> [ch05-01-defining-structs.md](https://github.com/rust-lang/book/blob/main/src/ch05-01-defining-structs.md)
> <br>
> commit 4f7799e3b3f0510440050f74af3dd75545c2dd23
> commit dd7e05275822d6cf790bcdae6983b3234141b5e7
结构体和我们在[“元组类型”][tuples]部分论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
@ -22,7 +22,7 @@
<span class="caption">示例 5-2创建 `User` 结构体的实例</span>
为了从结构体中获取某个特定的值,可以使用点号。如果我们只想要用户的邮箱地址,可以用 `user1.email`要更改结构体中的值,如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。示例 5-3 展示了如何改变一个可变的 `User` 实例 `email` 字段的值:
为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用 `user1.email`。如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。示例 5-3 展示了如何改变一个可变的 `User` 实例 `email` 字段的值:
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs:here}}
@ -88,7 +88,7 @@
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs}}
```
注意 `black``origin` 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段有着相同的类型。例如,一个获取 `Color` 类型参数的函数不能接受 `Point` 作为参数,即便这两个类型都由三个 `i32` 值组成。在其他方面,元组结构体实例类似于元组:可以将其解构为单独的部分,也可以使用 `.` 后跟索引来访问单独的值,等等。
注意 `black``origin` 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段可能有着相同的类型。例如,一个获取 `Color` 类型参数的函数不能接受 `Point` 作为参数,即便这两个类型都由三个 `i32` 值组成。在其他方面,元组结构体实例类似于元组,你可以将它们解构为单独的部分,也可以使用 `.` 后跟索引来访问单独的值,等等。
### 没有任何字段的类单元结构体

@ -2,7 +2,7 @@
> [ch05-02-example-structs.md](https://github.com/rust-lang/book/blob/main/src/ch05-02-example-structs.md)
> <br>
> commit 15aef431579a3d2f2bac8cc25445ece1c8e9808c
> commit dd7e05275822d6cf790bcdae6983b3234141b5e7
为了理解何时会需要使用结构体,让我们编写一个计算长方形面积的程序。我们会从单独的变量开始,接着重构程序直到使用结构体替代他们为止。
@ -64,7 +64,7 @@
函数 `area` 现在被定义为接收一个名叫 `rectangle` 的参数,其类型是一个结构体 `Rectangle` 实例的不可变借用。第四章讲到过,我们希望借用结构体而不是获取它的所有权,这样 `main` 函数就可以保持 `rect1` 的所有权并继续使用它,所以这就是为什么在函数签名和调用的地方会有 `&`
`area` 函数访问 `Rectangle` 实例的 `width``height` 字段。`area` 的函数签名现在明确的阐述了我们的意图:使用 `Rectangle``width``height` 字段,计算 `Rectangle` 的面积。这表明宽高是相互联系的,并为这些值提供了描述性的名称而不是使用元组的索引值 `0``1` 。结构体胜在更清晰明了。
`area` 函数访问 `Rectangle` 实例的 `width``height` 字段(注意,访问对结构体的引用的字段不会移动字段的所有权,这就是为什么你经常看到对结构体的引用)。`area` 的函数签名现在明确的阐述了我们的意图:使用 `Rectangle``width``height` 字段,计算 `Rectangle` 的面积。这表明宽高是相互联系的,并为这些值提供了描述性的名称而不是使用元组的索引值 `0``1` 。结构体胜在更清晰明了。
### 通过派生 trait 增加实用功能
@ -128,7 +128,7 @@ Rust **确实** 包含了打印出调试信息的功能,不过我们必须为
{{#include ../listings/ch05-using-structs-to-structure-related-data/output-only-02-pretty-debug/output.txt}}
```
另一种使用 `Debug` 格式打印数值的方法是使用 [`dbg!` 宏][dbg]。`dbg!` 宏接收一个表达式的所有权,打印出代码中调用 dbg! 宏时所在的文件和行号,以及该表达式的结果值,并返回该值的所有权。
另一种使用 `Debug` 格式打印数值的方法是使用 [`dbg!` 宏][dbg]。`dbg!` 宏接收一个表达式的所有权(与 `println!` 宏相反,后者接收的是引用),打印出代码中调用 dbg! 宏时所在的文件和行号,以及该表达式的结果值,并返回该值的所有权。
> 注意:调用 `dbg!` 宏会打印到标准错误控制台流(`stderr`),与 `println!` 不同,后者会打印到标准输出控制台流(`stdout`)。我们将在[第十二章 “将错误信息写入标准错误而不是标准输出” 一节][err]中更多地讨论 `stderr``stdout`

@ -2,7 +2,7 @@
> [ch05-03-method-syntax.md](https://github.com/rust-lang/book/blob/main/src/ch05-03-method-syntax.md)
> <br>
> commit 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa4
> commit dd7e05275822d6cf790bcdae6983b3234141b5e7
**方法**method与函数类似它们使用 `fn` 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义(或者是枚举或 trait 对象的上下文,将分别在第六章和第十七章讲解),并且它们第一个参数总是 `self`,它代表调用该方法的结构体实例。
@ -104,7 +104,7 @@ Can rect1 hold rect3? false
所有在 `impl` 块中定义的函数被称为 **关联函数***associated functions*),因为它们与 `impl` 后面命名的类型相关。我们可以定义不以 `self` 为第一参数的关联函数(因此不是方法),因为它们并不作用于一个结构体的实例。我们已经使用了一个这样的函数:在 `String` 类型上定义的 `String::from` 函数。
不是方法的关联函数经常被用作返回一个结构体新实例的构造函数,例如我们可以提供一个关联函数,它接受一个维度参数并且同时作为宽和高,这样可以更轻松的创建一个正方形 `Rectangle` 而不必指定两次同样的值:
不是方法的关联函数经常被用作返回一个结构体新实例的构造函数。这些函数的名称通常为 `new` `new` 并不是一个关键字。例如我们可以提供一个叫做 `square` 关联函数,它接受一个维度参数并且同时作为宽和高,这样可以更轻松的创建一个正方形 `Rectangle` 而不必指定两次同样的值:
<span class="filename">文件名: src/main.rs</span>
@ -112,6 +112,8 @@ Can rect1 hold rect3? false
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-03-associated-functions/src/main.rs:here}}
```
关键字 `Self` 在函数的返回类型中代指在 `impl` 关键字后出现的类型,在这里是 `Rectangle`
使用结构体名和 `::` 语法来调用这个关联函数:比如 `let sq = Rectangle::square(3);`。这个函数位于结构体的命名空间中:`::` 语法用于关联函数和模块创建的命名空间。第七章会讲到模块。
### 多个 `impl`

@ -2,8 +2,6 @@
> [ch06-00-enums.md](https://github.com/rust-lang/book/blob/main/src/ch06-00-enums.md)
> <br>
> commit 40c98a5118d2ba93ce9fd39c313bcbce5597818d
> commit c76f1b4d011fe59fc4f5e6f258070fc40d9921e4
本章介绍 **枚举***enumerations*),也被称作 *enums*。枚举允许你通过列举可能的 **成员***variants* 来定义一个类型。首先,我们会定义并使用一个枚举来展示它是如何连同数据一起编码信息的。接下来,我们会探索一个特别有用的枚举,叫做 `Option`,它代表一个值要么是某个值要么什么都不是。然后会讲到在 `match` 表达式中用模式匹配,针对不同的枚举值编写相应要执行的代码。最后会介绍 `if let`,另一个简洁方便处理代码中枚举的结构。
枚举是一个很多语言都有的功能不过不同语言中其功能各不相同。Rust 的枚举与 F#、OCaml 和 Haskell 这样的函数式编程语言中的 **代数数据类型***algebraic data types*)最为相似。

@ -2,9 +2,11 @@
> [ch06-01-defining-an-enum.md](https://github.com/rust-lang/book/blob/main/src/ch06-01-defining-an-enum.md)
> <br>
> commit d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c
> commit c76f1b4d011fe59fc4f5e6f258070fc40d9921e4
枚举是一个不同于结构体的定义自定义数据类型的方式。让我们看看一个需要诉诸于代码的场景,来考虑为何此时使用枚举更为合适且实用。假设我们要处理 IP 地址。目前被广泛使用的两个主要 IP 标准IPv4version four和 IPv6version six。这是我们的程序可能会遇到的所有可能的 IP 地址类型:所以可以 **枚举** 出所有可能的值,这也正是此枚举名字的由来。
结构体给予你将字段和数据聚合在一起的方法,像 `Rectangle` 结构体有 `width``height` 两个字段。而枚举给予你将一个值成为一个集合之一的方法。比如,我们想让 `Rectangle` 是一些形状的集合,包含 `Circle``Triangle` 。为了做到这个Rust提供了枚举类型。
让我们看看一个需要诉诸于代码的场景,来考虑为何此时使用枚举更为合适且实用。假设我们要处理 IP 地址。目前被广泛使用的两个主要 IP 标准IPv4version four和 IPv6version six。这是我们的程序可能会遇到的所有可能的 IP 地址类型:所以可以 **枚举** 出所有可能的值,这也正是此枚举名字的由来。
任何一个 IP 地址要么是 IPv4 的要么是 IPv6 的而且不能两者都是。IP 地址的这个特性使得枚举数据结构非常适合这个场景因为枚举值只可能是其中一个成员。IPv4 和 IPv6 从根本上讲仍是 IP 地址,所以当代码在处理适用于任何类型的 IP 地址的场景时应该把它们当作相同的类型。
@ -116,7 +118,9 @@ enum IpAddr {
### `Option` 枚举和其相对于空值的优势
这一部分会分析一个 `Option` 的案例,`Option` 是标准库定义的另一个枚举。`Option` 类型应用广泛因为它编码了一个非常普遍的场景,即一个值要么有值要么没值。例如,如果请求一个包含项的列表的第一个值,会得到一个值,如果请求一个空的列表,就什么也不会得到。从类型系统的角度来表达这个概念就意味着编译器需要检查是否处理了所有应该处理的情况,这样就可以避免在其他编程语言中非常常见的 bug。
这一部分会分析一个 `Option` 的案例,`Option` 是标准库定义的另一个枚举。`Option` 类型应用广泛因为它编码了一个非常普遍的场景,即一个值要么有值要么没值。
例如,如果请求一个包含项的列表的第一个值,会得到一个值,如果请求一个空的列表,就什么也不会得到。从类型系统的角度来表达这个概念就意味着编译器需要检查是否处理了所有应该处理的情况,这样就可以避免在其他编程语言中非常常见的 bug。
编程语言的设计经常要考虑包含哪些功能但考虑排除哪些功能也很重要。Rust 并没有很多其他语言中有的空值功能。**空值***Null* )是一个值,它代表没有值。在有空值的语言中,变量总是这两种状态之一:空值和非空值。
@ -154,7 +158,7 @@ enum Option<T> {
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/src/main.rs:here}}
```
`some_number` 的类型是 `Option<i32>`。`some_string` 的类型是 `Option<&str>`,这(与 `some_number`)是一个不同的类型。因为我们在 `Some` 成员中指定了值Rust 可以推断其类型。对于 `absent_number` Rust 需要我们指定 `Option` 整体的类型,因为编译器只通过 `None` 值无法推断出 `Some` 成员保存的值的类型。这里我们告诉 Rust 希望 `absent_number``Option<i32>` 类型的。
`some_number` 的类型是 `Option<i32>`。`some_char` 的类型是 `Option<char>`,这(与 `some_number`)是一个不同的类型。因为我们在 `Some` 成员中指定了值Rust 可以推断其类型。对于 `absent_number` Rust 需要我们指定 `Option` 整体的类型,因为编译器只通过 `None` 值无法推断出 `Some` 成员保存的值的类型。这里我们告诉 Rust 希望 `absent_number``Option<i32>` 类型的。
当有一个 `Some` 值时,我们就知道存在一个值,而这个值保存在 `Some` 中。当有个 `None` 值时,在某种意义上,它跟空值具有相同的意义:并没有一个有效的值。那么,`Option<T>` 为什么就比空值要好呢?

@ -2,7 +2,7 @@
> [ch06-02-match.md](https://github.com/rust-lang/book/blob/main/src/ch06-02-match.md)
> <br>
> commit db403a8bdfe5223d952737f54b0d9651b3e6ae1d
> commit c76f1b4d011fe59fc4f5e6f258070fc40d9921e4
Rust 有一个叫做 `match` 的极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成;第十八章会涉及到所有不同种类的模式以及它们的作用。`match` 的力量来源于模式的表现力以及编译器检查,它确保了所有可能的情况都得到处理。
@ -24,7 +24,7 @@ Rust 有一个叫做 `match` 的极为强大的控制流运算符,它允许我
每个分支相关联的代码是一个表达式,而表达式的结果值将作为整个 `match` 表达式的返回值。
如果分支代码较短的话通常不使用大括号,正如示例 6-3 中的每个分支都只是返回一个值。如果想要在分支中运行多行代码,可以使用大括号。例如,如下代码在每次使用`Coin::Penny` 调用时都会打印出 “Lucky penny!”,同时仍然返回代码块最后的值,`1`
如果分支代码较短的话通常不使用大括号,正如示例 6-3 中的每个分支都只是返回一个值。如果想要在分支中运行多行代码,可以使用大括号,而分支后的逗号是可选的。例如,如下代码在每次使用`Coin::Penny` 调用时都会打印出 “Lucky penny!”,同时仍然返回代码块最后的值,`1`
```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/src/main.rs:here}}
@ -94,7 +94,7 @@ Rust 有一个叫做 `match` 的极为强大的控制流运算符,它允许我
### 匹配是穷尽的
`match` 还有另一方面需要讨论。考虑一下 `plus_one` 函数的这个版本,它有一个 bug 并不能编译:
`match` 还有另一方面需要讨论:这些分支必须覆盖了所有的可能性。考虑一下 `plus_one` 函数的这个版本,它有一个 bug 并不能编译:
```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/src/main.rs:here}}
@ -122,7 +122,7 @@ Rust 知道我们没有覆盖所有可能的情况甚至知道哪些模式被忘
Rust 还提供了一个模式,当我们不想使用通配模式获取的值时,请使用 `_` ,这是一个特殊的模式,可以匹配任意值而不绑定到该值。这告诉 Rust 我们不会使用这个值,所以 Rust 也不会警告我们存在未使用的变量。
让我们改变游戏规则,当你掷出的值不是 3 或 7 的时候,你必须再次掷出。这种情况下我们不需要使用这个值,所以我们改动代码使用 `_` 来替代变量 `other`
让我们改变游戏规则:现在,当你掷出的值不是 3 或 7 的时候,你必须再次掷出。这种情况下我们不需要使用这个值,所以我们改动代码使用 `_` 来替代变量 `other`
```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs:here}}
@ -130,7 +130,7 @@ Rust 还提供了一个模式,当我们不想使用通配模式获取的值时
这个例子也满足穷举性要求,因为我们在最后一个分支中明确地忽略了其他的值。我们没有忘记处理任何东西。
让我们再次改变游戏规则,如果你掷出 3 或 7 以外的值,你的回合将无事发生。我们可以使用单元值(在[“元组类型”][tuples]<!-- ignore -->一节中提到的空元组)作为 `_` 分支的代码:
最后,让我们再次改变游戏规则,如果你掷出 3 或 7 以外的值,你的回合将无事发生。我们可以使用单元值(在[“元组类型”][tuples]<!-- ignore -->一节中提到的空元组)作为 `_` 分支的代码:
```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/src/main.rs:here}}

Loading…
Cancel
Save