Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


x-i18n: generated_at: “2026-03-01T13:38:13Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: dcf589530b27653579874f189bf572600a3061712964f525a06844642a2defb6 source_path: ch03-05-control-flow.md workflow: 16

控制流 (Control Flow)

Control Flow

根据条件是否为 true 来运行某些代码,以及在条件为 true 时重复运行某些代码的能力,是大多数编程语言的基本构建模块。在 Rust 中,让你控制执行流最常见的结构是 if 表达式和循环。

The ability to run some code depending on whether a condition is true and the ability to run some code repeatedly while a condition is true are basic building blocks in most programming languages. The most common constructs that let you control the flow of execution of Rust code are if expressions and loops.

if 表达式 (if Expressions)

if Expressions

if 表达式允许你根据条件对代码进行分支。你提供一个条件,然后声明:“如果满足此条件,运行此代码块。如果不满足此条件,则不运行此代码块。”

An if expression allows you to branch your code depending on conditions. You provide a condition and then state, “If this condition is met, run this block of code. If the condition is not met, do not run this block of code.”

在你的 projects 目录下创建一个名为 branches 的新项目来探索 if 表达式。在 src/main.rs 文件中,输入以下内容:

Create a new project called branches in your projects directory to explore the if expression. In the src/main.rs file, input the following:

文件名: src/main.rs

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-26-if-true/src/main.rs}}
}

所有 if 表达式都以关键字 if 开头,后跟一个条件。在这个例子中,条件检查变量 number 的值是否小于 5。我们将条件为 true 时要执行的代码块放在条件之后的花括号内。与 if 表达式中的条件相关联的代码块有时被称为“分支 (arms)”,就像我们在第 2 章“比较猜测数字与秘密数字”部分讨论过的 match 表达式中的分支一样。

All if expressions start with the keyword if, followed by a condition. In this case, the condition checks whether or not the variable number has a value less than 5. We place the block of code to execute if the condition is true immediately after the condition inside curly brackets. Blocks of code associated with the conditions in if expressions are sometimes called arms, just like the arms in match expressions that we discussed in the “Comparing the Guess to the Secret Number” section of Chapter 2.

可选地,我们还可以包含一个 else 表达式,我们在这里选择了这样做,以便在条件求值为 false 时为程序提供另一个可执行的代码块。如果你不提供 else 表达式且条件为 false,程序将直接跳过 if 块并继续执行下一段代码。

Optionally, we can also include an else expression, which we chose to do here, to give the program an alternative block of code to execute should the condition evaluate to false. If you don’t provide an else expression and the condition is false, the program will just skip the if block and move on to the next bit of code.

尝试运行此代码;你应该会看到以下输出:

Try running this code; you should see the following output:

{{#include ../listings/ch03-common-programming-concepts/no-listing-26-if-true/output.txt}}

让我们尝试将 number 的值更改为使条件为 false 的值,看看会发生什么:

Let’s try changing the value of number to a value that makes the condition false to see what happens:

{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-27-if-false/src/main.rs:here}}

再次运行程序,查看输出:

Run the program again, and look at the output:

{{#include ../listings/ch03-common-programming-concepts/no-listing-27-if-false/output.txt}}

还值得注意的是,这段代码中的条件“必须”是一个 bool。如果条件不是 bool,我们会得到一个错误。例如,尝试运行以下代码:

It’s also worth noting that the condition in this code must be a bool. If the condition isn’t a bool, we’ll get an error. For example, try running the following code:

文件名: src/main.rs

{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/src/main.rs}}

这次 if 条件求得的值为 3,Rust 抛出了一个错误:

The if condition evaluates to a value of 3 this time, and Rust throws an error:

{{#include ../listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt}}

该错误表明 Rust 期望得到一个 bool 但得到了一个整数。与 Ruby 和 JavaScript 等语言不同,Rust 不会自动尝试将非布尔类型转换为布尔类型。你必须显式地始终为 if 提供一个布尔值作为其条件。例如,如果我们希望 if 代码块仅在数字不等于 0 时运行,我们可以将 if 表达式更改为:

The error indicates that Rust expected a bool but got an integer. Unlike languages such as Ruby and JavaScript, Rust will not automatically try to convert non-Boolean types to a Boolean. You must be explicit and always provide if with a Boolean as its condition. If we want the if code block to run only when a number is not equal to 0, for example, we can change the if expression to the following:

文件名: src/main.rs

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-29-if-not-equal-0/src/main.rs}}
}

运行这段代码将打印 number was something other than zero

Running this code will print number was something other than zero.

使用 else if 处理多个条件 (Handling Multiple Conditions with else if)

Handling Multiple Conditions with else if

你可以通过在 else if 表达式中组合 ifelse 来使用多个条件。例如:

You can use multiple conditions by combining if and else in an else if expression. For example:

文件名: src/main.rs

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-30-else-if/src/main.rs}}
}

这个程序有四条可能的路径。运行它后,你应该会看到以下输出:

This program has four possible paths it can take. After running it, you should see the following output:

{{#include ../listings/ch03-common-programming-concepts/no-listing-30-else-if/output.txt}}

当此程序执行时,它会依次检查每个 if 表达式,并执行第一个条件求值为 true 的代码体。注意,尽管 6 可以被 2 整除,但我们没有看到输出 number is divisible by 2,也没有看到来自 else 块的 number is not divisible by 4, 3, or 2 文本。这是因为 Rust 只执行第一个 true 条件对应的代码块,一旦找到一个,它甚至不会检查剩余的条件。

When this program executes, it checks each if expression in turn and executes the first body for which the condition evaluates to true. Note that even though 6 is divisible by 2, we don’t see the output number is divisible by 2, nor do we see the number is not divisible by 4, 3, or 2 text from the else block. That’s because Rust only executes the block for the first true condition, and once it finds one, it doesn’t even check the rest.

使用过多的 else if 表达式会使你的代码变得混乱,所以如果你有超过一个,你可能需要重构你的代码。第 6 章描述了 Rust 中一个强大的分支结构,称为 match,用于处理这些情况。

Using too many else if expressions can clutter your code, so if you have more than one, you might want to refactor your code. Chapter 6 describes a powerful Rust branching construct called match for these cases.

let 语句中使用 if (Using if in a let Statement)

Using if in a let Statement

因为 if 是一个表达式,我们可以将其放在 let 语句的右侧,将结果分配给一个变量,如示例 3-2 所示。

Because if is an expression, we can use it on the right side of a let statement to assign the outcome to a variable, as in Listing 3-2.

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-02/src/main.rs}}
}

number 变量将根据 if 表达式的结果绑定一个值。运行此代码看看会发生什么:

The number variable will be bound to a value based on the outcome of the if expression. Run this code to see what happens:

{{#include ../listings/ch03-common-programming-concepts/listing-03-02/output.txt}}

请记住,代码块求值得出其中最后一个表达式的值,而数字本身也是表达式。在这种情况下,整个 if 表达式的值取决于执行哪个代码块。这意味着 if 的每个分支可能产生的结果必须具有相同的类型;在示例 3-2 中,if 分支和 else 分支的结果都是 i32 整数。如果类型不匹配,如下例所示,我们将得到一个错误:

Remember that blocks of code evaluate to the last expression in them, and numbers by themselves are also expressions. In this case, the value of the whole if expression depends on which block of code executes. This means the values that have the potential to be results from each arm of the if must be the same type; in Listing 3-2, the results of both the if arm and the else arm were i32 integers. If the types are mismatched, as in the following example, we’ll get an error:

文件名: src/main.rs

{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/src/main.rs}}

当我们尝试编译这段代码时,会得到一个错误。ifelse 分支的值类型不兼容,Rust 准确地指出了程序中出现问题的位置:

When we try to compile this code, we’ll get an error. The if and else arms have value types that are incompatible, and Rust indicates exactly where to find the problem in the program:

{{#include ../listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt}}

if 块中的表达式求值得出一个整数,而 else 块中的表达式求值得出一个字符串。这行不通,因为变量必须具有单一类型,而且 Rust 需要在编译时明确知道 number 变量是什么类型。知道 number 的类型可以让编译器验证在使用 number 的每个地方该类型是否有效。如果 number 的类型仅在运行时确定,Rust 将无法做到这一点;如果编译器必须跟踪任何变量的多种假设类型,它将变得更加复杂,并且对代码提供的保证也会减少。

The expression in the if block evaluates to an integer, and the expression in the else block evaluates to a string. This won’t work, because variables must have a single type, and Rust needs to know definitively at compile time what type the number variable is. Knowing the type of number lets the compiler verify the type is valid everywhere we use number. Rust wouldn’t be able to do that if the type of number was only determined at runtime; the compiler would be more complex and would make fewer guarantees about the code if it had to keep track of multiple hypothetical types for any variable.

使用循环重复执行 (Repetition with Loops)

Repetition with Loops

多次执行一个代码块通常很有用。为了完成这项任务,Rust 提供了几种“循环 (loops)”,它们会运行循环体内的代码直到结束,然后立即重新从头开始。为了实验循环,让我们创建一个名为 loops 的新项目。

It’s often useful to execute a block of code more than once. For this task, Rust provides several loops, which will run through the code inside the loop body to the end and then start immediately back at the beginning. To experiment with loops, let’s make a new project called loops.

Rust 有三种循环:loopwhilefor。让我们逐一尝试。

Rust has three kinds of loops: loop, while, and for. Let’s try each one.

使用 loop 重复代码 (Repeating Code with loop)

loop 关键字告诉 Rust 一遍又一遍地执行一个代码块,直到你显式地告诉它停止。

The loop keyword tells Rust to execute a block of code over and over again either forever or until you explicitly tell it to stop.

作为一个例子,修改 loops 目录下的 src/main.rs 文件,使其看起来像这样:

As an example, change the src/main.rs file in your loops directory to look like this:

文件名: src/main.rs

{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-loop/src/main.rs}}

当我们运行此程序时,我们会看到 again! 被不断打印,直到我们手动停止程序。大多数终端支持键盘快捷键 ctrl-C 来中断陷入死循环的程序。试一试:

When we run this program, we’ll see again! printed over and over continuously until we stop the program manually. Most terminals support the keyboard shortcut ctrl-C to interrupt a program that is stuck in a continual loop. Give it a try:

$ cargo run
   Compiling loops v0.1.0 (file:///projects/loops)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s
     Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!

符号 ^C 代表你按下 ctrl-C 的位置。

The symbol ^C represents where you pressed ctrl-C.

你可能会也可能不会在 ^C 之后看到打印出的 again! 单词,这取决于代码在接收到中断信号时处于循环的哪个位置。

You may or may not see the word again! printed after the ^C, depending on where the code was in the loop when it received the interrupt signal.

幸运的是,Rust 还提供了一种使用代码跳出循环的方法。你可以在循环中放置 break 关键字来告诉程序何时停止执行循环。回想一下,我们在第 2 章“猜测正确后退出”部分中在猜谜游戏中执行了此操作,以便在用户通过猜测正确数字赢得游戏时退出程序。

Fortunately, Rust also provides a way to break out of a loop using code. You can place the break keyword within the loop to tell the program when to stop executing the loop. Recall that we did this in the guessing game in the “Quitting After a Correct Guess” section of Chapter 2 to exit the program when the user won the game by guessing the correct number.

我们还在猜谜游戏中使用了 continue,它在循环中告诉程序跳过此迭代中循环的任何剩余代码,并进入下一次迭代。

We also used continue in the guessing game, which in a loop tells the program to skip over any remaining code in this iteration of the loop and go to the next iteration.

从循环中返回值 (Returning Values from Loops)

loop 的用途之一是重试你已知可能会失败的操作,例如检查线程是否已完成其作业。你可能还需要将该操作的结果从循环传出给代码的其余部分。为此,你可以在用于停止循环的 break 表达式之后添加你想要返回的值;该值将从循环中返回,以便你可以使用它,如下所示:

One of the uses of a loop is to retry an operation you know might fail, such as checking whether a thread has completed its job. You might also need to pass the result of that operation out of the loop to the rest of your code. To do this, you can add the value you want returned after the break expression you use to stop the loop; that value will be returned out of the loop so that you can use it, as shown here:

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs}}
}

在循环之前,我们声明了一个名为 counter 的变量并将其初始化为 0。然后,我们声明一个名为 result 的变量来保存从循环返回的值。在循环的每次迭代中,我们都将 1 加到 counter 变量上,然后检查 counter 是否等于 10。如果是,我们使用 break 关键字并带上值 counter * 2。在循环之后,我们使用分号结束将值分配给 result 的语句。最后,我们打印 result 中的值,在这个例子中是 20

Before the loop, we declare a variable named counter and initialize it to 0. Then, we declare a variable named result to hold the value returned from the loop. On every iteration of the loop, we add 1 to the counter variable, and then check whether the counter is equal to 10. When it is, we use the break keyword with the value counter * 2. After the loop, we use a semicolon to end the statement that assigns the value to result. Finally, we print the value in result, which in this case is 20.

你也可以从循环内部 return。虽然 break 只退出当前循环,但 return 总是退出当前函数。

You can also return from inside a loop. While break only exits the current loop, return always exits the current function.

使用循环标签进行消除歧义 (Disambiguating with Loop Labels)

如果你有循环嵌套循环,breakcontinue 将应用于该点最内层的循环。你可以选择在循环上指定一个“循环标签 (loop label)”,然后将其与 breakcontinue 一起使用,以指定这些关键字应用于带标签的循环,而不是最内层的循环。循环标签必须以单引号开头。这是一个带有两个嵌套循环的示例:

If you have loops within loops, break and continue apply to the innermost loop at that point. You can optionally specify a loop label on a loop that you can then use with break or continue to specify that those keywords apply to the labeled loop instead of the innermost loop. Loop labels must begin with a single quote. Here’s an example with two nested loops:

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs}}
}

外层循环具有标签 'counting_up,它将从 0 数到 2。没有标签的内层循环从 10 倒数到 9。第一个没有指定标签的 break 将仅退出内层循环。break 'counting_up; 语句将退出外层循环。这段代码打印:

The outer loop has the label 'counting_up, and it will count up from 0 to 2. The inner loop without a label counts down from 10 to 9. The first break that doesn’t specify a label will exit the inner loop only. The break 'counting_up; statement will exit the outer loop. This code prints:

{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/output.txt}}

使用 while 简化条件循环 (Streamlining Conditional Loops with while)

程序通常需要在循环中评估一个条件。当条件为 true 时,循环运行。当条件不再为 true 时,程序调用 break 停止循环。可以使用 loopifelsebreak 的组合来实现这种行为;如果你愿意,现在可以在程序中尝试一下。然而,这种模式非常常见,以至于 Rust 为其提供了一个内置的语言结构,称为 while 循环。在示例 3-3 中,我们使用 while 使程序循环三次,每次倒数,然后在循环之后打印一条消息并退出。

A program will often need to evaluate a condition within a loop. While the condition is true, the loop runs. When the condition ceases to be true, the program calls break, stopping the loop. It’s possible to implement behavior like this using a combination of loop, if, else, and break; you could try that now in a program, if you’d like. However, this pattern is so common that Rust has a built-in language construct for it, called a while loop. In Listing 3-3, we use while to loop the program three times, counting down each time, and then, after the loop, to print a message and exit.

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-03/src/main.rs}}
}

如果你使用 loopifelsebreak,这种结构消除了很多必要的嵌套,并且更清晰。只要条件求值为 true,代码就会运行;否则,它将退出循环。

This construct eliminates a lot of nesting that would be necessary if you used loop, if, else, and break, and it’s clearer. While a condition evaluates to true, the code runs; otherwise, it exits the loop.

使用 for 遍历集合 (Looping Through a Collection with for)

你可以选择使用 while 结构来遍历集合(如数组)的元素。例如,示例 3-4 中的循环打印数组 a 中的每个元素。

You can choose to use the while construct to loop over the elements of a collection, such as an array. For example, the loop in Listing 3-4 prints each element in the array a.

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-04/src/main.rs}}
}

在这里,代码对数组中的元素进行计数。它从索引 0 开始,然后循环直到达到数组中的最后一个索引(即当 index < 5 不再为 true 时)。运行此代码将打印数组中的每个元素:

Here, the code counts up through the elements in the array. It starts at index 0 and then loops until it reaches the final index in the array (that is, when index < 5 is no longer true). Running this code will print every element in the array:

{{#include ../listings/ch03-common-programming-concepts/listing-03-04/output.txt}}

如预期的那样,所有五个数组值都出现在终端中。尽管 index 会在某个时刻达到 5,但循环在尝试从数组中获取第六个值之前就会停止执行。

All five array values appear in the terminal, as expected. Even though index will reach a value of 5 at some point, the loop stops executing before trying to fetch a sixth value from the array.

然而,这种方法容易出错;如果索引值或测试条件不正确,我们可能会导致程序恐慌。例如,如果你将 a 数组的定义更改为包含四个元素,但忘记将条件更新为 while index < 4,代码就会恐慌。它的速度也很慢,因为编译器会添加运行时代码,以便在每次循环迭代时执行索引是否在数组范围内的条件检查。

However, this approach is error-prone; we could cause the program to panic if the index value or test condition is incorrect. For example, if you changed the definition of the a array to have four elements but forgot to update the condition to while index < 4, the code would panic. It’s also slow, because the compiler adds runtime code to perform the conditional check of whether the index is within the bounds of the array on every iteration through the loop.

作为一个更简洁的替代方案,你可以使用 for 循环,并为集合中的每一项执行某些代码。for 循环看起来像示例 3-5 中的代码。

As a more concise alternative, you can use a for loop and execute some code for each item in a collection. A for loop looks like the code in Listing 3-5.

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-05/src/main.rs}}
}

当我们运行这段代码时,我们会看到与示例 3-4 相同的输出。更重要的是,我们现在提高了代码的安全性,并消除了因超出数组末尾或没数到头而遗漏某些项而可能产生的 bug。由 for 循环生成的机器代码也可以更高效,因为不需要在每次迭代时将索引与数组长度进行比较。

When we run this code, we’ll see the same output as in Listing 3-4. More importantly, we’ve now increased the safety of the code and eliminated the chance of bugs that might result from going beyond the end of the array or not going far enough and missing some items. Machine code generated from for loops can be more efficient as well because the index doesn’t need to be compared to the length of the array at every iteration.

使用 for 循环,如果你更改了数组中值的数量,你不需要像使用示例 3-4 中的方法那样记得更改任何其他代码。

Using the for loop, you wouldn’t need to remember to change any other code if you changed the number of values in the array, as you would with the method used in Listing 3-4.

for 循环的安全性及其简洁性使其成为 Rust 中最常用的循环结构。即使在你想运行某些代码特定次数的情况下,比如在示例 3-3 中使用 while 循环的倒数例子,大多数 Rustaceans 也会使用 for 循环。实现的方法是使用标准库提供的 Range,它可以按顺序生成从一个数字开始、在另一个数字之前结束的所有数字。

The safety and conciseness of for loops make them the most commonly used loop construct in Rust. Even in situations in which you want to run some code a certain number of times, as in the countdown example that used a while loop in Listing 3-3, most Rustaceans would use a for loop. The way to do that would be to use a Range, provided by the standard library, which generates all numbers in sequence starting from one number and ending before another number.

以下是使用 for 循环和另一个我们尚未谈到的方法 rev(用于反转范围)实现的倒数样子:

Here’s what the countdown would look like using a for loop and another method we’ve not yet talked about, rev, to reverse the range:

文件名: src/main.rs

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs}}
}

这段代码看起来更漂亮了,不是吗?

This code is a bit nicer, isn’t it?

总结 (Summary)

Summary

你做到了!这是一个相当大的章节:你学习了变量、标量和复合数据类型、函数、注释、if 表达式和循环!为了练习本章讨论的概念,请尝试构建程序来执行以下操作:

You made it! This was a sizable chapter: You learned about variables, scalar and compound data types, functions, comments, if expressions, and loops! To practice with the concepts discussed in this chapter, try building programs to do the following:

  • 在华氏温度和摄氏温度之间转换。

  • 生成第 n 个斐波那契数。

  • 打印圣诞颂歌“圣诞节的十二天 (The Twelve Days of Christmas)”的歌词,利用歌曲中的重复性。

  • Convert temperatures between Fahrenheit and Celsius.

  • Generate the nth Fibonacci number.

  • Print the lyrics to the Christmas carol “The Twelve Days of Christmas,” taking advantage of the repetition in the song.

当你准备好继续前进时,我们将讨论 Rust 中一个在其他编程语言中通常“不存在”的概念:所有权 (ownership)。

When you’re ready to move on, we’ll talk about a concept in Rust that doesn’t commonly exist in other programming languages: ownership.