mirror of
https://github.com/KaiserY/trpl-zh-cn
synced 2024-11-09 00:43:59 +08:00
check to ch03-05
This commit is contained in:
parent
23450ed8f8
commit
72b6ceabbc
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
> [ch03-04-comments.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-04-comments.md)
|
> [ch03-04-comments.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-04-comments.md)
|
||||||
> <br>
|
> <br>
|
||||||
> commit d06a6a181fd61704cbf7feb55bc61d518c6469f9
|
> commit d4c77666f480edfb960cc9b11a31c42f4b90c745
|
||||||
|
|
||||||
所有编程语言都力求使它们的代码易于理解,不过有时需要提供额外的解释。在这种情况下,程序员在源码中留下记录,或者 **注释**(*comments*),编译器会忽略它们不过其他阅读代码的人可能会用得上。
|
所有编程语言都力求使其代码易于理解,不过有时需要提供额外的解释。在这种情况下,程序员在源码中留下记录,或者 **注释**(*comments*),编译器会忽略它们不过其他阅读代码的人可能会用得上。
|
||||||
|
|
||||||
这是一个注释的例子:
|
这是一个简单的注释的例子:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Hello, world.
|
// Hello, world.
|
||||||
```
|
```
|
||||||
|
|
||||||
在 Rust 中,注释必须以两道斜杠开始并持续到本行的结尾。对于超过一行的注释,需要在每一行都加上`//`,像这样:
|
在 Rust 中,注释必须以两道斜杠开始,并持续到本行的结尾。对于超过一行的注释,需要在每一行都加上 `//`,像这样:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// So we’re doing something complicated here, long enough that we need
|
// So we’re doing something complicated here, long enough that we need
|
||||||
@ -30,7 +30,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
不过你会经常看到它们被以这种格式使用,也就是位于它所解释的代码行的上面一行:
|
不过你会经常看到它们用于这种格式,也就是位于它所解释的代码行的上面一行:
|
||||||
|
|
||||||
<span class="filename">文件名: src/main.rs</span>
|
<span class="filename">文件名: src/main.rs</span>
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> [ch03-05-control-flow.md](https://github.com/rust-lang/book/blob/master/src/ch03-05-control-flow.md)
|
> [ch03-05-control-flow.md](https://github.com/rust-lang/book/blob/master/src/ch03-05-control-flow.md)
|
||||||
> <br>
|
> <br>
|
||||||
> commit 2e269ff82193fd65df8a87c06561d74b51ac02f7
|
> commit ec65990849230388e4ce4db5b7a0cb8a0f0d60e2
|
||||||
|
|
||||||
通过条件是不是为真来决定是否执行某些代码,或者根据条件是否为真来重复运行一段代码是大部分编程语言的基本组成部分。Rust 代码中最常见的用来控制执行流的结构是 `if` 表达式和循环。
|
通过条件是不是为真来决定是否执行某些代码,或者根据条件是否为真来重复运行一段代码是大部分编程语言的基本组成部分。Rust 代码中最常见的用来控制执行流的结构是 `if` 表达式和循环。
|
||||||
|
|
||||||
@ -28,13 +28,14 @@ fn main() {
|
|||||||
|
|
||||||
<!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 -->
|
<!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 -->
|
||||||
|
|
||||||
所有 `if` 表达式以 `if` 关键字开头,它后跟一个条件。在这个例子中,条件检查 `number` 是否有一个小于 5 的值。在条件为真时希望执行的代码块位于紧跟条件之后的大括号中。`if` 表达式中与条件关联的代码块有时被叫做 *arms*,就像第二章 “比较猜测与秘密数字” 部分中讨论到的 `match` 表达式中分支一样。也可以包含一个可选的 `else` 表达式来提供一个在条件为假时应当执行的代码块,这里我们就这么做了。如果不提供 `else` 表达式并且条件为假时,程序会直接忽略 `if` 代码块并继续执行下面的代码。
|
所有的 `if` 表达式都以 `if` 关键字开头,其后跟一个条件。在这个例子中,条件检查变量 `number` 是否有一个小于 5 的值。在条件为真时希望执行的代码块位于紧跟条件之后的大括号中。`if` 表达式中与条件关联的代码块有时被叫做 *arms*,就像第二章 “比较猜测与秘密数字” 部分中讨论到的 `match` 表达式中分支一样。也可以包含一个可选的 `else` 表达式来提供一个在条件为假时应当执行的代码块,这里我们就这么做了。如果不提供 `else` 表达式并且条件为假时,程序会直接忽略 `if` 代码块并继续执行下面的代码。
|
||||||
|
|
||||||
尝试运行代码,应该能看到如下输出:
|
尝试运行代码,应该能看到如下输出:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$ cargo run
|
$ cargo run
|
||||||
Compiling branches v0.1.0 (file:///projects/branches)
|
Compiling branches v0.1.0 (file:///projects/branches)
|
||||||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
|
||||||
Running `target/debug/branches`
|
Running `target/debug/branches`
|
||||||
condition was true
|
condition was true
|
||||||
```
|
```
|
||||||
@ -50,11 +51,12 @@ let number = 7;
|
|||||||
```text
|
```text
|
||||||
$ cargo run
|
$ cargo run
|
||||||
Compiling branches v0.1.0 (file:///projects/branches)
|
Compiling branches v0.1.0 (file:///projects/branches)
|
||||||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
|
||||||
Running `target/debug/branches`
|
Running `target/debug/branches`
|
||||||
condition was false
|
condition was false
|
||||||
```
|
```
|
||||||
|
|
||||||
另外值得注意的是代码中的条件 **必须** 是 `bool`。如果想看看条件不是 `bool` 值时会发生什么,尝试运行如下代码:
|
另外值得注意的是代码中的条件 **必须** 是 `bool` 值。如果想看看条件不是 `bool` 值时会发生什么,尝试运行如下代码:
|
||||||
|
|
||||||
<span class="filename">文件名: src/main.rs</span>
|
<span class="filename">文件名: src/main.rs</span>
|
||||||
|
|
||||||
@ -124,17 +126,18 @@ fn main() {
|
|||||||
```text
|
```text
|
||||||
$ cargo run
|
$ cargo run
|
||||||
Compiling branches v0.1.0 (file:///projects/branches)
|
Compiling branches v0.1.0 (file:///projects/branches)
|
||||||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
|
||||||
Running `target/debug/branches`
|
Running `target/debug/branches`
|
||||||
number is divisible by 3
|
number is divisible by 3
|
||||||
```
|
```
|
||||||
|
|
||||||
当执行这个程序,它按顺序检查每个 `if` 表达式并执行第一个条件为真的代码块。注意即使 6 可以被 2 整除,也不会出现 `number is divisible by 2` 的输出,更不会出现 `else` 块中的 `number is not divisible by 4, 3, or 2`。原因是 Rust 只会执行第一个条件为真的代码块,并且它一旦找到一个以后,就不会检查剩下的条件了。
|
当执行这个程序,它按顺序检查每个 `if` 表达式并执行第一个条件为真的代码块。注意即使 6 可以被 2 整除,也不会出现 `number is divisible by 2` 的输出,更不会出现 `else` 块中的 `number is not divisible by 4, 3, or 2`。原因是 Rust 只会执行第一个条件为真的代码块,并且一旦它找到一个以后,甚至就不会检查剩下的条件了。
|
||||||
|
|
||||||
使用过多的 `else if` 表达式会使代码显得杂乱无章,所以如果有多于一个 `else if`,最好重构代码。为此第六章会介绍 Rust 中一个叫做 `match` 的强大的分支结构(branching construct)。
|
使用过多的 `else if` 表达式会使代码显得杂乱无章,所以如果有多于一个 `else if`,最好重构代码。为此第六章会介绍 Rust 中一个叫做 `match` 的强大的分支结构(branching construct)。
|
||||||
|
|
||||||
#### 在 `let` 语句中使用 `if`
|
#### 在 `let` 语句中使用 `if`
|
||||||
|
|
||||||
因为 `if` 是一个表达式,我们可以在 `let` 语句的右侧使用它,例如在示例 3-4 中:
|
因为 `if` 是一个表达式,我们可以在 `let` 语句的右侧使用它,例如在示例 3-2 中:
|
||||||
|
|
||||||
<span class="filename">文件名: src/main.rs</span>
|
<span class="filename">文件名: src/main.rs</span>
|
||||||
|
|
||||||
@ -151,18 +154,19 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<span class="caption">示例 3-4:将 `if` 的返回值赋值给一个变量</span>
|
<span class="caption">示例 3-2:将 `if` 的返回值赋值给一个变量</span>
|
||||||
|
|
||||||
`number` 变量将会绑定到基于 `if` 表达式结果的值。运行这段代码看看会出现什么:
|
`number` 变量将会绑定到基于 `if` 表达式结果的值。运行这段代码看看会出现什么:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$ cargo run
|
$ cargo run
|
||||||
Compiling branches v0.1.0 (file:///projects/branches)
|
Compiling branches v0.1.0 (file:///projects/branches)
|
||||||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
|
||||||
Running `target/debug/branches`
|
Running `target/debug/branches`
|
||||||
The value of number is: 5
|
The value of number is: 5
|
||||||
```
|
```
|
||||||
|
|
||||||
还记得代码块的值是其最后一个表达式的值,以及数字本身也是一个表达式吗。在这个例子中,整个 `if` 表达式的值依赖哪个代码块被执行。这意味着 `if` 的每个分支的可能的返回值都必须是相同类型;在示例 3-4 中,`if` 分支和 `else` 分支的结果都是 `i32` 整型。不过如果像下面的例子那样这些类型并不匹配会怎么样呢?
|
还记得代码块的值是其最后一个表达式的值,以及数字本身也是一个表达式吗。在这个例子中,整个 `if` 表达式的值依赖哪个代码块被执行。这意味着 `if` 的每个分支的可能的返回值都必须是相同类型;在示例 3-2 中,`if` 分支和 `else` 分支的结果都是 `i32` 整型。如果它们的类型不匹配,如下面这个例子,则会出现一个错误:
|
||||||
|
|
||||||
<span class="filename">文件名: src/main.rs</span>
|
<span class="filename">文件名: src/main.rs</span>
|
||||||
|
|
||||||
@ -195,7 +199,7 @@ error[E0308]: if and else have incompatible types
|
|||||||
| |_____^ expected integral variable, found reference
|
| |_____^ expected integral variable, found reference
|
||||||
|
|
|
|
||||||
= note: expected type `{integer}`
|
= note: expected type `{integer}`
|
||||||
found type `&'static str`
|
found type `&str`
|
||||||
```
|
```
|
||||||
|
|
||||||
`if` 代码块的表达式返回一个整型,而 `else` 代码块返回一个字符串。这并不可行,因为变量必须只有一个类型。Rust 需要在编译时就确切的知道 `number` 变量的类型,这样它就可以在编译时证明其他使用 `number` 变量的地方它的类型是有效的。Rust 并不能够在 `number` 的类型只能在运行时确定的情况下工作;这样会使编译器变得更复杂而且只能为代码提供更少的保障,因为它不得不记录所有变量的多种可能的类型。
|
`if` 代码块的表达式返回一个整型,而 `else` 代码块返回一个字符串。这并不可行,因为变量必须只有一个类型。Rust 需要在编译时就确切的知道 `number` 变量的类型,这样它就可以在编译时证明其他使用 `number` 变量的地方它的类型是有效的。Rust 并不能够在 `number` 的类型只能在运行时确定的情况下工作;这样会使编译器变得更复杂而且只能为代码提供更少的保障,因为它不得不记录所有变量的多种可能的类型。
|
||||||
@ -227,6 +231,7 @@ fn main() {
|
|||||||
```text
|
```text
|
||||||
$ cargo run
|
$ cargo run
|
||||||
Compiling loops v0.1.0 (file:///projects/loops)
|
Compiling loops v0.1.0 (file:///projects/loops)
|
||||||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs
|
||||||
Running `target/debug/loops`
|
Running `target/debug/loops`
|
||||||
again!
|
again!
|
||||||
again!
|
again!
|
||||||
@ -235,13 +240,13 @@ again!
|
|||||||
^Cagain!
|
^Cagain!
|
||||||
```
|
```
|
||||||
|
|
||||||
符号 `^C` 代表你在这按下了<span class="keystroke">ctrl-C</span>。在 `^C` 之后你可能看到 `again!` 也可能看不到,这依赖于在接收到终止信号时代码执行到了循环的何处。
|
符号 `^C` 代表你在这按下了<span class="keystroke">ctrl-C</span>。在 `^C` 之后你可能看到也可能看不到 `again!` ,这依赖于在接收到终止信号时代码执行到了循环的何处。
|
||||||
|
|
||||||
幸运的是,Rust 提供了另一个更可靠的方式来退出循环。可以使用 `break` 关键字来告诉程序何时停止执行循环。还记得我们在第二章猜猜看游戏的 “猜测正确后退出” 部分使用过它来在用户猜对数字赢得游戏后退出程序吗。
|
幸运的是,Rust 提供了另一个更可靠的方式来退出循环。可以使用 `break` 关键字来告诉程序何时停止执行循环。回忆一下在第二章猜猜看游戏的 “猜测正确后退出” 部分使用过它来在用户猜对数字赢得游戏后退出程序。
|
||||||
|
|
||||||
#### `while` 条件循环
|
#### `while` 条件循环
|
||||||
|
|
||||||
在程序中计算循环的条件也很常见。当条件为真,执行循环。当条件不再为真,调用 `break`停止循环。这个循环类型可以通过组合 `loop`、`if`、`else` 和 `break`来实现;如果你喜欢的话,现在就可以在程序中试试。
|
在程序中计算循环的条件也很常见。当条件为真,执行循环。当条件不再为真,调用 `break` 停止循环。这个循环类型可以通过组合 `loop`、`if`、`else` 和 `break` 来实现;如果你喜欢的话,现在就可以在程序中试试。
|
||||||
|
|
||||||
然而,这个模式太常见了以至于 Rust 为此提供了一个内建的语言结构,它被称为 `while` 循环。下面的例子使用了 `while`:程序循环三次,每次数字都减一。接着,在循环之后,打印出另一个信息并退出:
|
然而,这个模式太常见了以至于 Rust 为此提供了一个内建的语言结构,它被称为 `while` 循环。下面的例子使用了 `while`:程序循环三次,每次数字都减一。接着,在循环之后,打印出另一个信息并退出:
|
||||||
|
|
||||||
@ -265,7 +270,7 @@ fn main() {
|
|||||||
|
|
||||||
#### 使用 `for` 遍历集合
|
#### 使用 `for` 遍历集合
|
||||||
|
|
||||||
可以使用 `while` 结构来遍历一个元素集合,比如数组。如下:
|
可以使用 `while` 结构来遍历一个元素集合,比如数组。例如,看看如下的示例 3-3:
|
||||||
|
|
||||||
<span class="filename">文件名: src/main.rs</span>
|
<span class="filename">文件名: src/main.rs</span>
|
||||||
|
|
||||||
@ -282,13 +287,14 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<span class="caption">示例 3-5:使用 `while` 循环遍历集合中的每一个元素</span>
|
<span class="caption">示例 3-3:使用 `while` 循环遍历集合中的每一个元素</span>
|
||||||
|
|
||||||
这里代码对数组中的元素进行计数。它从索引 `0` 开始,并接着循环直到遇到数组的最后一个索引(这时,`index < 5` 不再为真)。运行这段代码会打印出数组中的每一个元素:
|
这里代码对数组中的元素进行计数。它从索引 `0` 开始,并接着循环直到遇到数组的最后一个索引(这时,`index < 5` 不再为真)。运行这段代码会打印出数组中的每一个元素:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$ cargo run
|
$ cargo run
|
||||||
Compiling loops v0.1.0 (file:///projects/loops)
|
Compiling loops v0.1.0 (file:///projects/loops)
|
||||||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
|
||||||
Running `target/debug/loops`
|
Running `target/debug/loops`
|
||||||
the value is: 10
|
the value is: 10
|
||||||
the value is: 20
|
the value is: 20
|
||||||
@ -301,7 +307,7 @@ the value is: 50
|
|||||||
|
|
||||||
不过这个过程是容易出错的;如果索引长度不正确会导致程序 panic。这也使程序更慢,因为编译器增加了运行时代码来对每次循环的每个元素进行条件检查。
|
不过这个过程是容易出错的;如果索引长度不正确会导致程序 panic。这也使程序更慢,因为编译器增加了运行时代码来对每次循环的每个元素进行条件检查。
|
||||||
|
|
||||||
可以使用 `for` 循环来对一个集合的每个元素执行一些代码,来作为一个更有效率的替代。`for` 循环看起来像这样:
|
可以使用 `for` 循环来对一个集合的每个元素执行一些代码,来作为一个更有效率的替代。`for` 循环看起来如示例 3-4 所示:
|
||||||
|
|
||||||
<span class="filename">文件名: src/main.rs</span>
|
<span class="filename">文件名: src/main.rs</span>
|
||||||
|
|
||||||
@ -315,13 +321,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<span class="caption">示例 3-6:使用 `for` 循环遍历集合中的每一个元素</span>
|
<span class="caption">示例 3-4:使用 `for` 循环遍历集合中的每一个元素</span>
|
||||||
|
|
||||||
当运行这段代码,将看到与示例 3-5 一样的输出。更为重要的是,我们增强了代码安全性并消除了出现可能会导致超出数组的结尾或遍历长度不够而缺少一些元素这类 bug 的机会。
|
当运行这段代码,将看到与示例 3-3 一样的输出。更为重要的是,我们增强了代码安全性并消除了出现可能会导致超出数组的结尾或遍历长度不够而缺少一些元素这类 bug 的机会。
|
||||||
|
|
||||||
例如,在示例 3-5 的代码中,如果从数组 `a` 中移除一个元素但忘记更新条件为 `while index < 4`,代码将会 panic。使用`for`循环的话,就不需要惦记着在更新数组元素数量时修改其他的代码了。
|
例如,在示例 3-3 的代码中,如果从数组 `a` 中移除一个元素但忘记更新条件为 `while index < 4`,代码将会 panic。使用`for`循环的话,就不需要惦记着在更新数组元素数量时修改其他的代码了。
|
||||||
|
|
||||||
`for` 循环的安全性和简洁性使得它在成为 Rust 中使用最多的循环结构。即使是在想要循环执行代码特定次数时,例如示例 3-5 中使用 `while` 循环的倒计时例子,大部分 Rustacean 也会使用 `for` 循环。这么做的方式是使用 `Range`,它是标准库提供的用来生成从一个数字开始到另一个数字之前结束的所有数字序列的类型。
|
`for` 循环的安全性和简洁性使得它在成为 Rust 中使用最多的循环结构。即使是在想要循环执行代码特定次数时,例如示例 3-3 中使用 `while` 循环的倒计时例子,大部分 Rustacean 也会使用 `for` 循环。这么做的方式是使用 `Range`,它是标准库提供的用来生成从一个数字开始到另一个数字之前结束的所有数字序列的类型。
|
||||||
|
|
||||||
下面是一个使用 `for` 循环来倒计时的例子,它还使用了一个我们还未讲到的方法,`rev`,用来反转 range:
|
下面是一个使用 `for` 循环来倒计时的例子,它还使用了一个我们还未讲到的方法,`rev`,用来反转 range:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user