mirror of
https://github.com/gnu4cn/rust-lang-zh_CN.git
synced 2026-08-19 12:43:28 +08:00
Updated src/programming_concepts/control_flow.md'.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
fn main() {
|
||||
loop {
|
||||
println! ("again!");
|
||||
for number in (1..4).rev() {
|
||||
println! ("{}!", number);
|
||||
}
|
||||
|
||||
println! ("LIFTOFF!!");
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str>{
|
||||
|
||||
*清单 12-17:遍历 `contents` 中的各行*
|
||||
|
||||
`lines` 方法会返回一个迭代器。我们将在 [第 13 章](../functional_features/iterators.md) 中,详细讨论迭代器,但请回想一下,咱们在 [清单 3-5](../programming_concepts/control_flow.md#listing-3-5) 中就已见过这种使用迭代器的方法,当时我们与迭代器一起使用了 `for` 循环,对集合中的各个元素执行一些代码。
|
||||
`lines` 方法会返回一个迭代器。我们将在 [第 13 章](../functional_features/iterators.md) 中,详细讨论迭代器,但请回想一下,咱们在 [清单 3-5](../programming_concepts/control_flow.md#listing_3-5) 中就已见过这种使用迭代器的方法,当时我们与迭代器一起使用了 `for` 循环,对集合中的各个元素执行一些代码。
|
||||
|
||||
|
||||
### 在各行中检索查询字符串
|
||||
|
||||
@@ -287,8 +287,7 @@ again!
|
||||
|
||||
### 从循环返回值
|
||||
|
||||
|
||||
`loop` 的用途之一,是重试咱们已知可能会失败的某项操作,例如检查某个线程是否已完成其作业。咱们可能还需要将该操作的结果,从循环中传递给咱们代码的其余部分。为此,咱们可以将这个咱们打算返回的值,添加在咱们用于停止循环的 `break` 表达式之后;该值将从循环中返回,以便咱们使用,如下所示:
|
||||
`loop` 的用途之一,是重试咱们知道可能失败的某项操作,例如检查某个线程是否已完成其作业。咱们可能还需要从循环传递出该操作的结果,到咱们代码的其余部分。要完成这一目的,咱们可将咱们打算返回的值,添加在咱们用于停止循环的 `break` 表达式后;该值将从循环中返回出来,以便咱们使用他,如下所示:
|
||||
|
||||
|
||||
```rust
|
||||
@@ -307,13 +306,38 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
在该循环之前,我们声明了一个名为 `counter` 的变量,并将其初始化为 `0`。 然后咱们声明了一个名为 `result` 的变量,用于保存自该循环返回的值。在循环的每一次迭代中,我们都会给那个 `counter` 变量加 `1`,然后检查这个 `counter` 是否等于 `10`。当他等于 `10` 时,我们使用了带有 `counter * 2` 值的 `break` 关键字。在这个循环结束后,我们使用了一个分号,结束那条把该值赋给 `result` 的语句。最后,我们打印了 `result` 中的值,本例中即为 `20`。
|
||||
在其中的循环前,我们声明一个名为 `counter` 的变量并初始化其为 `0`。 然后,咱们声明一个名为 `result` 的变量保存从该循环返回的值。在该循环的每一次迭代时,我们都给 `counter` 变量加 `1`,然后检查 `counter` 是否等于 `10`。当等于 `10` 时,我们使用带有 `counter * 2` 值的 `break` 关键字。在这个循环之后,我们使用分号结束指派该值到 `result` 的语句。最后,我们打印 `result` 中的值,在本例中为 `20`。
|
||||
|
||||
我们还可在循环内 `return`。`break` 只会退出当前循环,而 `return` 则始终会推出当前函数。
|
||||
|
||||
|
||||
> **译注**:这个示例还可写作如下。
|
||||
>
|
||||
>
|
||||
> ```rust
|
||||
> fn main() {
|
||||
> let mut counter = 0;
|
||||
>
|
||||
> let result = loop {
|
||||
> counter += 1;
|
||||
>
|
||||
> if counter == 10 {
|
||||
> break
|
||||
> counter * 2
|
||||
> }
|
||||
> };
|
||||
>
|
||||
> println! ("结果为:{result}");
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> 这似乎与 `break` 后的循环体代码不再执行相矛盾。也可理解为 `counter * 2` 表达式为 `break` 表达式的参数?
|
||||
|
||||
|
||||
### 以循环标签消除歧义
|
||||
|
||||
|
||||
如果咱们有着循环内的循环,`break` 和 `continue` 就会应用于那个地方最内层的循环。咱们可以选择在某个循环上,指定出一个随后可与 `break` 或 `continue` 一起使用的 *循环标签,loop label*,来指定这些关键字适用于某个带标签的循环,而不是最内层的那个循环。循环标签必须以单引号开头。下面是个带有两个嵌套循环的示例:
|
||||
当咱们有着循环内的循环(译注:嵌套循环)时,`break` 和 `continue` 就会应用于该处的最内层循环。咱们可选择在某个循环上指定一个 *循环标签,loop lable*,随后咱们可与 `break` 或 `continue` 一起使用,指定这两个关键字会应用到某个带标签的循环,而不是最内层循环。循环标签必须以单引号开头。下面是两个嵌套循环下的一个示例:
|
||||
|
||||
|
||||
```rust
|
||||
@@ -343,14 +367,14 @@ fn main() {
|
||||
```
|
||||
|
||||
|
||||
其中的外层循环有着标签 `'counting_up`,同时他将从 `0` 计数到 `2`。而其中的内层循环不带标签,会从 `10` 计数到 `9`。未指定标签的第一个 `break` 语句,将只会退出那个内部循环。而那个 `break 'counting_up;` 语句,则会将外层循环退出。此代码会打印出:
|
||||
其中外层循环有着标签 `'counting_up`,他将从 `0` 计数到 `2`。不带标签的内存循环会从 `10` 倒计数到 `9`。未指定标签的第一个 `break`,将只退出内层循环。那个 `break 'counting_up;` 语句将退出外层循环。这段代码会打印:
|
||||
|
||||
|
||||
```console
|
||||
$ cargo run
|
||||
Compiling loops v0.1.0 (C:\tools\msys64\home\Lenny.Peng\rust-lang-zh_CN\projects\loops)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.77s
|
||||
Running `target\debug\loops.exe`
|
||||
Compiling loops v0.1.0 (/home/hector/rust-lang-zh_CN/projects/loops)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s
|
||||
Running `target/debug/loops`
|
||||
计数 = 0
|
||||
剩余 = 10
|
||||
剩余 = 9
|
||||
@@ -363,14 +387,12 @@ $ cargo run
|
||||
```
|
||||
|
||||
|
||||
### 使用 `while` 的条件循环
|
||||
### `while` 下的简化条件循环
|
||||
|
||||
**Conditional Loops with `while`**
|
||||
|
||||
|
||||
程序经常需要计算循环内的某个条件。当该条件为 `true` 时,循环就会运行。当条件不再为 `true` 时,程序就会调用 `break`,停止该循环。使用 `loop`、`if`、`else` 和 `break` 的组合,实现类似这样的行为使可行的;如果咱们愿意,现在就可以在程序中尝试一下。不过,这种模式是如此常见,以致 Rust 为其提供了一种内置的语言结构,称为 `while` 循环。在下面清单 3-3 中,我们使用 `while` 将该程序循环三次,每次会倒计时,然后在循环结束后,打印一条信息并退出。
|
||||
程序将经常需要评估循环内的条件。当条件为 `true` 时,循环运行。当条件不再为 `true` 时,程序调用 `break`,停止循环。使用 `loop`、`if`、`else` 与 `break` 的组合实现像是这样的行为是可行的;若咱们愿意,咱们现在就可以在程序中尝试这种做法。然而,这种模式如此常见,以至于 Rust 为其提供了一种内置的语言结构,称为 `while` 循环。在下面清单 3-3 中,我们使用 `while` 循环该程序三次,每次都倒数,然后在循环之后打印一条消息并退出。
|
||||
|
||||
|
||||
<a name="listing_3-3"></a>
|
||||
文件名:`src/main.rs`
|
||||
|
||||
```rust
|
||||
@@ -387,18 +409,15 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
*清单 3-3:使用 `while` 循环在条件保持为真期间运行代码*
|
||||
*清单 3-3:使用 `while` 循环在条件求值为 `true` 时运行代码*
|
||||
|
||||
|
||||
这种结构,消除了咱们在使用 `loop`、`if`、`else`、及 `break` 时,必然会有的大量嵌套,且更为清晰。在某个条件计算为 `true` 期间,代码就会运行;否则,他会退出那个循环。
|
||||
这种结构消除了咱们在使用 `loop`、`if`、`else`、及 `break` 时所需的大量嵌套,且更为清晰。在条件求值为 `true` 时,代码运行;否则,他会退出循环。
|
||||
|
||||
|
||||
### 使用 `for` 遍历集合
|
||||
|
||||
**Looping Through a Collection with `for`**
|
||||
|
||||
|
||||
咱们可以选择使用 `while` 结构,来遍历某种集合(比如数组)的元素。作为示例,下面清单 3-4 中的循环,会打印出数组 `a` 中的各个元素。
|
||||
咱们可选择使用 `while` 结构遍历集合中的元素,比如数组。例如,下面清单 3-4 中的循环会打印数组 `a` 中的各个元素。
|
||||
|
||||
|
||||
文件名:`src/main.rs`
|
||||
@@ -416,17 +435,17 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
*清单 3-4:使用 `while` 循环遍历某个集合的各个元素*
|
||||
*清单 3-4:使用 `while` 循环遍历集合中的各个元素*
|
||||
|
||||
|
||||
此处,代码会对数组中的元素,进行向上计数。他会从索引 `0` 处开始,然后循环直到他到达数组中的最终索引(即,当 `index < 5` 不再为 `true` 时)。运行这段代码,将打印出该数组中的每个元素:
|
||||
此处,代码会对数组中的元素向上计数。他会于索引 `0` 处开始然后循环,直到他到达数组中的最终索引(即,当 `index < 5` 不再为 `true` 时)。运行这段代码将打印该数组中的每个元素:
|
||||
|
||||
|
||||
```console
|
||||
$ cargo run
|
||||
Compiling loops v0.1.0 (C:\tools\msys64\home\Lenny.Peng\rust-lang-zh_CN\projects\loops)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.80s
|
||||
Running `target\debug\loops.exe`
|
||||
Compiling loops v0.1.0 (/home/hector/rust-lang-zh_CN/projects/loops)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s
|
||||
Running `target/debug/loops`
|
||||
the value is: 10
|
||||
the value is: 20
|
||||
the value is: 30
|
||||
@@ -435,13 +454,14 @@ the value is: 50
|
||||
```
|
||||
|
||||
|
||||
如预期那样,所有五个数组值都会出现在终端中。即使 `index` 在某一时刻会达到 `5`,这个循环也会在尝试从该数组中,获取第六个值前,停止执行。
|
||||
正如预期那样,所有五个数组值都出现在终端中。即使 `index` 将在某一时刻达到 `5`,这个循环也会尝试获取该数组中第六个值前停止执行。
|
||||
|
||||
但是,这种方法容易出错;如果索引值或测试条件不正确,我们可能会导致程序终止运行。例如,如果咱们将 `a` 这个数组的定义,改为有四个元素,但忘记将那个条件更新为 `while index < 4`,这段代码就会终止运行。此外,由于编译器会添加一些在循环的每次迭代时,执行索引是否在数组边界内条件检查的代码,因此该程序还会运行很慢。
|
||||
但是,这种方法很容易出错;当索引值或测试条件不正确时,我们就会导致程序终止运行。例如,若咱们将 `a` 这个数组的定义改为有着四个元素,却忘记将条件更新为 `while index < 4` 时,则这段代码将终止运行。他还很慢,因为编译器会添加一些运行时代码,在循环的每次迭代时,执行索引是否在数组边界内的条件检查。
|
||||
|
||||
作为一种更简洁的替代方法,咱们可以使用 `for` 循环,并为集合中的每个项目执行一些代码。`for` 循环会看起来如下清单 3-5 中的代码。
|
||||
作为更简洁的替代方法,咱们可使用 `for` 循环,并对集合中的每个项目执行一些代码。`for` 循环会看起来如下清单 3-5 中的代码。
|
||||
|
||||
|
||||
<a name="listing_3-5"></a>
|
||||
文件名:`src/main.rs`
|
||||
|
||||
```rust
|
||||
@@ -454,16 +474,16 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<a name="listing-3-5"></a> *清单 3-5:使用 `for` 循环遍历某个集合的各个元素*
|
||||
*清单 3-5:使用 `for` 循环遍历集合中的各个元素*
|
||||
|
||||
|
||||
当咱们运行这段代码时,我们将看到与清单 3-4 同样的输出。更重要的是,我们现在提高了代码的安全性,消除了可能由超出数组末尾,或因遍历不足远而遗漏某些项目等所可能导致的错误。
|
||||
当咱们运行这段代码时,我们将看到与清单 3-4 同样的输出。更重要的是,我们现在提高了代码的安全性,并消除了超出数组末尾,或因遍历不足远而遗漏某些项目等可能导致的 bug 的可能性。自 `for` 循环生成的机器码也会更加高效,因为索引不需要在每次迭代时都与数组长度比较。
|
||||
|
||||
使用 `for` 循环,如果咱们更改了数组中值的个数,就不需要像清单 3-4 中使用的方法那样,记得修改任何其他代码。
|
||||
使用 `for` 循环时,当咱们修改了数组中值的个数时,咱们将不需要向使用 [清单 3-4](#listing_3-4) 中用到的方法中那样,记住修改任何其他代码。
|
||||
|
||||
`for` 循环的安全性和简洁性,使其成为 Rust 中最常用的循环结构。即使是在咱们打算运行某些代码特定次数的情况下,如清单 3-3 中,使用 `while` 循环的倒计时示例中那样,大多数 Rustaceans,也会使用 `for` 循环。而要完成那个操作的方法,会用到标准库提供的 `Range`,他可以按顺序生成从一个数字开始,到另一个数字结束前的所有数字。
|
||||
`for` 循环的安全性和简洁性,使其成为 Rust 中最常用到的循环结构。即使是在咱们打算运行某些代码一定次数的情形下,如清单 3-3 中使用 `while` 循环的倒计时示例中,大多数 Rustaceans 也会使用 `for` 循环。实现这点的方法,是使用由标准库提供的 `Range`,他会按顺序生成从一个数字开始到另一个数字前结束的所有数字。
|
||||
|
||||
下面是使用 `for` 循环,和另一个我们尚未讨论过的反转该范围的方法 `rev`,的倒计时看起来的样子:
|
||||
下面是使用 `for` 循环和我们尚未讨论过的另一个反转范围的方法 `rev` 的倒计数,看起来的样子:
|
||||
|
||||
|
||||
文件名:`src/main.rs`
|
||||
@@ -478,22 +498,19 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
这段代码更漂亮一些,不是吗?
|
||||
这段代码好一点,不是吗?
|
||||
|
||||
|
||||
## 本章小结
|
||||
|
||||
咱们做到了!这是蔚为壮观的一章:咱们学习了变量、标量与复合数据类型、函数、注释、`if` 表达式和循环!要练习这一章中讨论的概念,请尝试构建程序完成以下操作:
|
||||
|
||||
咱们做到了!本章内容客观:咱们学习了变量、标量与复合数据类型、函数、注释、`if` 表达式和循环!为练习本章所讨论的概念,请尝试编写程序来完成以下操作:
|
||||
|
||||
- 在华氏温度和摄氏温度之间进行转换;
|
||||
|
||||
- 转换华氏和摄氏之间的温度;
|
||||
- 生成第 n 个斐波拉基数;
|
||||
|
||||
- 利用圣诞颂歌 “The Twelve Days of Christmas” 中的重复,而打印出歌词;
|
||||
- 利用圣诞颂歌 “The Twelve Days of Christmas” 中的重复,而打印出其歌词;
|
||||
|
||||
|
||||
当咱们准备好继续前进时,我们将讨论 Rust 中,一个在其他编程语言中并 *不* 常见的概念:所有权,ownership。
|
||||
当咱们准备好继续前进时,我们将讨论 Rust 中,一个在其他编程语言中 *不* 常见的概念:所有权。
|
||||
|
||||
|
||||
## 练习答案
|
||||
|
||||
Reference in New Issue
Block a user