文章目录
- [Rust 控制流](#Rust 控制流)
-
- [`if` 表达式](#
if
表达式) - 循环实现重复
-
- [用 `loop` 重复代码](#用
loop
重复代码) - 从循环返回值
- 循环标签用于区分多层循环
- [while 条件循环](#while 条件循环)
- [用 `for` 循环遍历集合](#用
for
循环遍历集合)
- [用 `loop` 重复代码](#用
- [`if` 表达式](#
Rust 控制流

在大多数编程语言中,根据条件是否为真来运行某些代码,以及在条件为真时重复运行某些代码,是最基本的构建块。Rust 中最常见的控制代码执行流程的结构是 if
表达式和循环。
if
表达式
if
表达式允许你根据条件分支代码。你提供一个条件,然后说明:"如果满足这个条件,就运行这段代码块。如果不满足,就不运行。"
在你的项目目录下新建一个名为 branches 的项目,来探索 if 表达式。在 src/main.rs 文件中输入以下内容:
文件名:src/main.rs
rust
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
所有 if
表达式都以关键字 if
开头,后跟一个条件。本例中,条件检查变量 number
是否小于 5。如果条件为真,则立即执行大括号内的代码块。与 match
表达式类似,if
表达式中与条件相关联的代码块有时也被称为"分支"。
你还可以选择包含 else
表达式(本例已包含),为条件为假时提供另一段代码。如果没有 else
,且条件为假,程序会跳过 if
块,继续执行后续代码。
运行这段代码,你会看到如下输出:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/branches`
condition was true
尝试将 number 的值改为使条件为假的值:
rust
let number = 7;
再次运行程序,输出如下:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/branches`
condition was false
需要注意的是,if
的条件必须是 bool
类型。如果不是 bool
布尔类型,会报错。例如,尝试运行以下代码:
文件名:src/main.rs
此代码无法编译!
rust
fn main() {
let number = 3;
if number {
println!("number was three");
}
}
if
条件这次是 3
,Rust 会报错:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
error[E0308]: mismatched types
--> src/main.rs:4:8
|
4 | if number {
| ^^^^^^ expected `bool`, found integer
错误提示 Rust 期望的是 bool
类型,但得到的是整数。与 Ruby 和 JavaScript 不同,Rust 不会自动将非布尔类型转换为布尔类型。你必须显式地为 if
提供布尔条件。例如,如果只想在 number
不等于 0 时运行 if
代码块,可以这样写:
文件名:src/main.rs
rust
fn main() {
let number = 3;
if number != 0 {
println!("number was something other than zero");
}
}
运行后会输出 number was something other than zero。
使用 else if
处理多个条件
你可以通过 else if
组合 if
和 else
来处理多个条件。例如:
文件名:src/main.rs
rust
fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}
该程序有四条可能的执行路径。运行后输出:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/branches`
number is divisible by 3
程序会依次检查每个 if
条件,执行第一个为真的分支。即使 6 能被 2 整除,也不会输出 number is divisible by 2,因为 Rust 只会执行第一个为真的分支,之后的不会再检查。
如果 else if
太多,代码会变得混乱。此时可以考虑用 Rust 更强大的分支结构 match
(第 6 章会介绍)。
在 let
语句中使用 if
因为 if 是表达式,可以用在 let 语句右侧,将结果赋值给变量,如下例所示:
文件名:src/main.rs
rust
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}
number
变量的值取决于 if
表达式的结果。运行后输出:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30s
Running `target/debug/branches`
The value of number is: 5
记住,代码块的值是最后一个表达式的值,数字本身也是表达式。本例中,if
表达式的值取决于哪个分支被执行。if
和 else
的返回值类型必须一致;如果类型不一致,会报错:
文件名:src/main.rs
此代码无法编译!
rust
fn main() {
let condition = true;
let number = if condition { 5 } else { "six" };
println!("The value of number is: {number}");
}
编译时会报错,提示类型不兼容:
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:4:44
|
4 | let number = if condition { 5 } else { "six" };
| - ^^^^^ expected integer, found `&str`
| |
| expected because of this
if
分支返回整数,else
分支返回字符串。Rust 需要在编译时确定变量类型,不能在运行时才决定。
循环实现重复
有时需要多次执行一段代码。为此,Rust 提供了多种循环结构,会不断执行循环体中的代码。让我们新建一个名为 loops 的项目来实验循环。
Rust 有三种循环:loop
、while
和 for
。下面分别介绍。
用 loop
重复代码
loop
关键字让 Rust 不断执行一段代码,直到你显式让它停止。
例如,将 loops
目录下的 src/main.rs 改为:
文件名:src/main.rs
rust
fn main() {
loop {
println!("again!");
}
}
运行后会不断输出 again!,直到你手动终止程序。大多数终端可以用 ctrl-c 中断死循环。试试看:
$ 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
。你可能会看到 ^C 后还有 again!,这取决于中断时循环执行到哪。
幸运的是,Rust 也允许你用 break
关键字跳出循环。你可以在循环中用 break
让程序停止循环。我们在第 2 章的猜数字游戏中就用过 break
来退出循环。
在循环中还可以用 continue
跳过本次循环剩余代码,直接进入下一次循环。
从循环返回值
有时需要在循环中重试某个可能失败的操作,并将结果传递给后续代码。你可以在 break
后加上要返回的值,这个值会作为循环的返回值。例如:
rust
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}");
}
在循环前声明 counter
变量,初始为 0。result
变量保存循环返回的值。每次循环 counter
加 1,判断是否等于 10。如果是,用 break
返回 counter * 2
。循环结束后,打印 result
的值(20)。
你也可以在循环中用 return
直接返回,return
会退出当前函数,而 break 只退出当前循环。
循环标签用于区分多层循环
如果循环嵌套,break
和 continue
默认作用于最内层循环。你可以为循环加标签(以单引号开头),用 break
或 continue
指定作用于哪个循环。例如:
rust
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}
外层循环标签为 'counting_up
,会从 0 数到 2。内层循环从 10 数到 9。未指定标签的 break
只退出内层循环,break
'counting_up
; 会退出外层循环。输出如下:
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.58s
Running `target/debug/loops`
count = 0
remaining = 10
remaining = 9
count = 1
remaining = 10
remaining = 9
count = 2
remaining = 10
End count = 2
while 条件循环
程序经常需要在循环中判断条件。条件为真时循环,条件为假时 break 退出。虽然可以用 loop
、if
、else
和 break
实现,但这种模式很常见,Rust 提供了 while 循环。如下例,使用 while
循环倒计时三次,循环结束后打印消息并退出。
文件名:src/main.rs
rust
fn main() {
let mut number = 3;
while number != 0 {
println!("{number}!");
number -= 1;
}
println!("LIFTOFF!!!");
}
这种写法比用 loop
、if
、else
、break
嵌套更简洁。只要条件为真就循环,否则退出。
用 for
循环遍历集合
你也可以用 while
遍历集合(如数组)。例如,下面的代码用 while
循环打印数组 a 的每个元素:
文件名:src/main.rs
rust
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("the value is: {}", a[index]);
index += 1;
}
}
输出:
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.32s
Running `target/debug/loops`
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50
虽然能正常输出,但这种写法容易出错。如果数组 a 改为 4 个元素,却忘了把条件改为 while index < 4
,程序会 panic。而且每次循环都要检查索引是否越界,效率较低。
更简洁安全的做法是用 for 循环遍历集合,如下所示:
文件名:src/main.rs
rust
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {element}");
}
}
输出与上例相同。更重要的是,这种写法更安全,不会越界,也不会漏掉元素。如果数组元素数量变化,也无需修改其他代码。
for
循环的安全性和简洁性使其成为 Rust 最常用的循环结构。即使只是重复执行代码多次,大多数 Rustacean 也会用 for
循环。例如倒计时,可以用标准库的 Range
生成序列,再用 rev
反转:
文件名:src/main.rs
rust
fn main() {
for number in (1..4).rev() {
println!("{number}!");
}
println!("LIFTOFF!!!");
}
这样写更优雅。