From aaa64649905fa54c97858de3a5f2b348d72e4423 Mon Sep 17 00:00:00 2001 From: Hector PENG Date: Sun, 8 Mar 2026 16:21:50 +0800 Subject: [PATCH] Updated src/programming_concepts/control_flow.md'. --- projects/loops/src/main.rs | 6 +- src/io_project/test_driven_dev.md | 2 +- src/programming_concepts/control_flow.md | 97 ++++++++++++++---------- 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/projects/loops/src/main.rs b/projects/loops/src/main.rs index 9d9b31c..cc6a870 100644 --- a/projects/loops/src/main.rs +++ b/projects/loops/src/main.rs @@ -1,5 +1,7 @@ fn main() { - loop { - println! ("again!"); + for number in (1..4).rev() { + println! ("{}!", number); } + + println! ("LIFTOFF!!"); } diff --git a/src/io_project/test_driven_dev.md b/src/io_project/test_driven_dev.md index f5a94f9..5c2a0b7 100644 --- a/src/io_project/test_driven_dev.md +++ b/src/io_project/test_driven_dev.md @@ -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` 循环,对集合中的各个元素执行一些代码。 ### 在各行中检索查询字符串 diff --git a/src/programming_concepts/control_flow.md b/src/programming_concepts/control_flow.md index 69d28c0..82c2e7e 100644 --- a/src/programming_concepts/control_flow.md +++ b/src/programming_concepts/control_flow.md @@ -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` 循环该程序三次,每次都倒数,然后在循环之后打印一条消息并退出。 + 文件名:`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 中的代码。 + 文件名:`src/main.rs` ```rust @@ -454,16 +474,16 @@ fn main() { } ``` - *清单 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 中,一个在其他编程语言中 *不* 常见的概念:所有权。 ## 练习答案