mirror of
https://github.com/KaiserY/trpl-zh-cn
synced 2024-11-14 04:41:49 +08:00
check to ch06-03
This commit is contained in:
parent
6f9c0d89a6
commit
cecbf32d79
@ -1,8 +1,8 @@
|
||||
## 定义并实例化结构体
|
||||
|
||||
> [ch05-01-defining-structs.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch05-01-defining-structs.md)
|
||||
> [ch05-01-defining-structs.md](https://github.com/rust-lang/book/blob/master/src/ch05-01-defining-structs.md)
|
||||
> <br>
|
||||
> commit c560db1e0145d5a64b9415c9cfe463c7dac31ab8
|
||||
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
|
||||
|
||||
结构体和我们在第三章讨论过的元组类似。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
|
||||
|
||||
@ -192,7 +192,7 @@ let origin = Point(0, 0, 0);
|
||||
|
||||
我们也可以定义一个没有任何字段的结构体!它们被称为 **类单元结构体**(*unit-like structs*)因为它们类似于 `()`,即 unit 类型。类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。我们将在第十章介绍 trait。
|
||||
|
||||
> ## 结构体数据的所有权
|
||||
> ### 结构体数据的所有权
|
||||
>
|
||||
> 在示例 5-1 中的 `User` 结构体的定义中,我们使用了自身拥有所有权的 `String` 类型而不是 `&str` 字符串 slice 类型。这是一个有意而为之的选择,因为我们想要这个结构体拥有它所有的数据,为此只要整个结构体是有效的话其数据也是有效的。
|
||||
>
|
||||
@ -200,7 +200,7 @@ let origin = Point(0, 0, 0);
|
||||
>
|
||||
> <span class="filename">文件名: src/main.rs</span>
|
||||
>
|
||||
> ```rust,ignore
|
||||
> ```rust,ignore,does_not_compile
|
||||
> struct User {
|
||||
> username: &str,
|
||||
> email: &str,
|
||||
|
@ -1,8 +1,8 @@
|
||||
## 一个使用结构体的示例程序
|
||||
|
||||
> [ch05-02-example-structs.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch05-02-example-structs.md)
|
||||
> [ch05-02-example-structs.md](https://github.com/rust-lang/book/blob/master/src/ch05-02-example-structs.md)
|
||||
> <br>
|
||||
> commit c560db1e0145d5a64b9415c9cfe463c7dac31ab8
|
||||
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
|
||||
|
||||
为了理解何时会需要使用结构体,让我们编写一个计算长方形面积的程序。我们会从单独的变量开始,接着重构程序直到使用结构体替代他们为止。
|
||||
|
||||
@ -111,7 +111,7 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
@ -149,7 +149,7 @@ error[E0277]: the trait bound `Rectangle: std::fmt::Display` is not satisfied
|
||||
error[E0277]: the trait bound `Rectangle: std::fmt::Debug` is not satisfied
|
||||
```
|
||||
|
||||
不过编译器又一次给出了一个有帮助的信息!
|
||||
不过编译器又一次给出了一个有帮助的信息:
|
||||
|
||||
```text
|
||||
`Rectangle` cannot be formatted using `:?`; if it is defined in your
|
||||
|
@ -1,8 +1,8 @@
|
||||
## 方法语法
|
||||
|
||||
> [ch05-03-method-syntax.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch05-03-method-syntax.md)
|
||||
> [ch05-03-method-syntax.md](https://github.com/rust-lang/book/blob/master/src/ch05-03-method-syntax.md)
|
||||
> <br>
|
||||
> commit c560db1e0145d5a64b9415c9cfe463c7dac31ab8
|
||||
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
|
||||
|
||||
**方法** 与函数类似:它们使用 `fn` 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义(或者是枚举或 trait 对象的上下文,将分别在第六章和第十七章讲解),并且它们第一个参数总是 `self`,它代表调用该方法的结构体实例。
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# 枚举和模式匹配
|
||||
|
||||
> [ch06-00-enums.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch06-00-enums.md)
|
||||
> [ch06-00-enums.md](https://github.com/rust-lang/book/blob/master/src/ch06-00-enums.md)
|
||||
> <br>
|
||||
> commit e3be64b3c034de029ae9e4f04e6d2742d799d2b1
|
||||
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
|
||||
|
||||
本章介绍 **枚举**(*enumerations*),也被称作 *enums*。枚举允许你通过列举可能的值来定义一个类型。首先,我们会定义并使用一个枚举来展示它是如何连同数据一起编码信息的。接下来,我们会探索一个特别有用的枚举,叫做 `Option`,它代表一个值要么是某个值要么什么都不是。然后会讲到在 `match` 表达式中用模式匹配,针对不同的枚举值编写相应要执行的代码。最后会介绍 `if let`,另一个简洁方便处理代码中枚举的结构。
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# 定义枚举
|
||||
|
||||
> [ch06-01-defining-an-enum.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch06-01-defining-an-enum.md)
|
||||
> [ch06-01-defining-an-enum.md](https://github.com/rust-lang/book/blob/master/src/ch06-01-defining-an-enum.md)
|
||||
> <br>
|
||||
> commit 923201d5117c45bf78ce433422b50e4de9bd9b11
|
||||
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
|
||||
|
||||
让我们看看一个需要诉诸于代码的场景,来考虑为何此时使用枚举更为合适且实用。假设我们要处理 IP 地址。目前被广泛使用的两个主要 IP 标准:IPv4(version four)和 IPv6(version six)。这是我们的程序可能会遇到的所有可能的 IP 地址类型:所以可以 **枚举** 出所有可能的值,这也正是此枚举名字的由来。
|
||||
|
||||
@ -157,7 +157,7 @@ enum Message {
|
||||
* `Write` 包含单独一个 `String`。
|
||||
* `ChangeColor` 包含三个 `i32`。
|
||||
|
||||
定义一个如示例 6-2 中所示那样的有关联值的枚举的方式和定义多个不同类型的结构体的方式很相像——除了枚举不使用 `struct` 关键字以及其所有成员都被组合在一起位于 `Message` 类型下。如下这些结构体可以包含与之前枚举成员中相同的数据:
|
||||
定义一个如示例 6-2 中所示那样的有关联值的枚举的方式和定义多个不同类型的结构体的方式很相像,除了枚举不使用 `struct` 关键字以及其所有成员都被组合在一起位于 `Message` 类型下。如下这些结构体可以包含与之前枚举成员中相同的数据:
|
||||
|
||||
```rust
|
||||
struct QuitMessage; // 类单元结构体
|
||||
@ -169,7 +169,7 @@ struct WriteMessage(String); // 元组结构体
|
||||
struct ChangeColorMessage(i32, i32, i32); // 元组结构体
|
||||
```
|
||||
|
||||
不过,如果我们使用不同的结构体,由于它们都有不同的类型,我们将不能像使用示例 6-2 中定义的 `Message` 枚举那样,轻易的定义一个能够处理这些不同类型的结构体的函数。因为使用枚举的情况下,“它们”是一个类型。
|
||||
不过,如果我们使用不同的结构体,由于它们都有不同的类型,我们将不能像使用示例 6-2 中定义的 `Message` 枚举那样,轻易的定义一个能够处理这些不同类型的结构体的函数,因为枚举是单独一个类型。
|
||||
|
||||
结构体和枚举还有另一个相似点:就像可以使用 `impl` 来为结构体定义方法那样,也可以在枚举上定义方法。这是一个定义于我们 `Message` 枚举上的叫做 `call` 的方法:
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
## `match` 控制流运算符
|
||||
|
||||
> [ch06-02-match.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch06-02-match.md)
|
||||
> [ch06-02-match.md](https://github.com/rust-lang/book/blob/master/src/ch06-02-match.md)
|
||||
> <br>
|
||||
> commit 18fd30d70f4d6ee67e0a808710bf7a3135ef7ed6
|
||||
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
|
||||
|
||||
Rust 有一个叫做 `match` 的极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成;第十八章会涉及到所有不同种类的模式以及它们的作用。`match` 的力量来源于模式的表现力以及编译器检查,它确保了所有可能的情况都得到处理。
|
||||
|
||||
@ -30,11 +30,11 @@ fn value_in_cents(coin: Coin) -> u32 {
|
||||
|
||||
<span class="caption">示例 6-3:一个枚举和一个以枚举成员作为模式的 `match` 表达式</span>
|
||||
|
||||
拆开 `value_in_cents` 函数中的 `match` 来看。首先,我们列出 `match` 关键字后跟一个表达式,在这个例子中是 `coin` 的值。这看起来非常像 `if` 使用的表达式,不过这里有一个非常大的区别:对于 `if`,表达式必须返回一个布尔值。而这里它可以是任何类型的。例子中的 `coin` 的类型是示例 6-3 中定义的 `Coin` 枚举。
|
||||
拆开 `value_in_cents` 函数中的 `match` 来看。首先,我们列出 `match` 关键字后跟一个表达式,在这个例子中是 `coin` 的值。这看起来非常像 `if` 使用的表达式,不过这里有一个非常大的区别:对于 `if`,表达式必须返回一个布尔值,而这里它可以是任何类型的。例子中的 `coin` 的类型是示例 6-3 中定义的 `Coin` 枚举。
|
||||
|
||||
接下来是 `match` 的分支。一个分支有两个部分:一个模式和一些代码。第一个分支的模式是值 `Coin::Penny` 而之后的 `=>` 运算符将模式和将要运行的代码分开。这里的代码就仅仅是值 `1`。每一个分支之间使用逗号分隔。
|
||||
|
||||
当 `match` 表达式执行时,它将结果值按顺序与每一个分支的模式相比较,如果模式匹配了这个值,这个模式相关联的代码将被执行。如果模式并不匹配这个值,将继续执行下一个分支,非常类似一个硬币分类器。可以拥有任意多的分支:示例 6-3 中的 `match` 有四个分支。
|
||||
当 `match` 表达式执行时,它将结果值按顺序与每一个分支的模式相比较。如果模式匹配了这个值,这个模式相关联的代码将被执行。如果模式并不匹配这个值,将继续执行下一个分支,非常类似一个硬币分类器。可以拥有任意多的分支:示例 6-3 中的 `match` 有四个分支。
|
||||
|
||||
每个分支相关联的代码是一个表达式,而表达式的结果值将作为整个 `match` 表达式的返回值。
|
||||
|
||||
@ -68,11 +68,11 @@ fn value_in_cents(coin: Coin) -> u32 {
|
||||
作为一个例子,让我们修改枚举的一个成员来存放数据。1999 年到 2008 年间,美帝在 25 美分的硬币的一侧为 50 个州的每一个都印刷了不同的设计。其他的硬币都没有这种区分州的设计,所以只有这些 25 美分硬币有特殊的价值。可以将这些信息加入我们的 `enum`,通过改变 `Quarter` 成员来包含一个 `State` 值,示例 6-4 中完成了这些修改:
|
||||
|
||||
```rust
|
||||
#[derive(Debug)] // So we can inspect the state in a minute
|
||||
#[derive(Debug)] // 这样可以可以立刻看到州的名称
|
||||
enum UsState {
|
||||
Alabama,
|
||||
Alaska,
|
||||
// ... etc
|
||||
// --snip--
|
||||
}
|
||||
|
||||
enum Coin {
|
||||
@ -157,8 +157,6 @@ Some(i) => Some(i + 1),
|
||||
|
||||
`Some(5)` 与 `Some(i)` 匹配吗?当然匹配!它们是相同的成员。`i` 绑定了 `Some` 中包含的值,所以 `i` 的值是 `5`。接着匹配分支的代码被执行,所以我们将 `i` 的值加一并返回一个含有值 `6` 的新 `Some`。
|
||||
|
||||
#### 匹配 `None`
|
||||
|
||||
接着考虑下示例 6-5 中 `plus_one` 的第二个调用,这里 `x` 是 `None`。我们进入 `match` 并与第一个分支相比较。
|
||||
|
||||
```rust,ignore
|
||||
@ -171,9 +169,9 @@ None => None,
|
||||
|
||||
### 匹配是穷尽的
|
||||
|
||||
`match` 还有另一方面需要讨论。考虑一下 `plus_one` 函数的这个版本:
|
||||
`match` 还有另一方面需要讨论。考虑一下 `plus_one` 函数的这个版本,它有一个 bug 并不能编译:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn plus_one(x: Option<i32>) -> Option<i32> {
|
||||
match x {
|
||||
Some(i) => Some(i + 1),
|
||||
|
@ -1,10 +1,10 @@
|
||||
## `if let` 简单控制流
|
||||
|
||||
> [ch06-03-if-let.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch06-03-if-let.md)
|
||||
> [ch06-03-if-let.md](https://github.com/rust-lang/book/blob/master/src/ch06-03-if-let.md)
|
||||
> <br>
|
||||
> commit 3f2a1bd8dbb19cc48b210fc4fb35c305c8d81b56
|
||||
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
|
||||
|
||||
`if let` 语法让我们以一种不那么冗长的方式结合 `if` 和 `let`,来处理只匹配一个模式的值而忽略其他模式的情况。考虑示例 6-6 中的程序,它匹配一个 `Option<u8>` 值并只希望当值为三时执行代码:
|
||||
`if let` 语法让我们以一种不那么冗长的方式结合 `if` 和 `let`,来处理只匹配一个模式的值而忽略其他模式的情况。考虑示例 6-6 中的程序,它匹配一个 `Option<u8>` 值并只希望当值为 3 时执行代码:
|
||||
|
||||
```rust
|
||||
let some_u8_value = Some(0u8);
|
||||
@ -27,7 +27,7 @@ if let Some(3) = some_u8_value {
|
||||
}
|
||||
```
|
||||
|
||||
`if let` 获取通过 `=` 分隔的一个模式和一个表达式。它的工作方式与 `match` 相同,这里的表达式对应 `match` 而模式则对应第一个分支。
|
||||
`if let` 获取通过等号分隔的一个模式和一个表达式。它的工作方式与 `match` 相同,这里的表达式对应 `match` 而模式则对应第一个分支。
|
||||
|
||||
使用 `if let` 意味着编写更少代码,更少的缩进和更少的样板代码。然而,这样会失去 `match` 强制要求的穷尽性检查。`match` 和 `if let` 之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user