控制流
能够根据条件是否为true
和
当 Condition 为true
是基本的构建块
在大多数编程语言中。可让您控制的最常见结构
Rust 代码的执行流程是if
表达式和循环。
if
表达 式
一if
expression 允许您根据条件对代码进行分支。你
提供一个条件,然后声明“如果满足此条件,则运行此块
的代码。如果不满足条件,请不要运行此代码块。
在 projects 目录中创建一个名为 branches 的新项目以进行浏览
这if
表达。在 src/main.rs 文件中,输入以下内容:
文件名: src/main.rs
fn main() { let number = 3; if number < 5 { println!("condition was true"); } else { println!("condition was false"); } }
都if
表达式以关键字if
,后跟一个 condition。在
在这种情况下,条件检查变量number
具有
值小于 5。如果条件为true
紧跟在大括号内的 condition 之后。代码块
与if
表达式有时称为 arms,
就像match
表达式中讨论的表达式
猜秘密数字“部分。
或者,我们还可以包含一个else
表达式,我们选择执行
在这里,为了给程序提供一个替代的代码块来执行,如果
condition 评估为false
.如果您未提供else
expression 和
条件为false
,程序将仅跳过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
设置为使条件false
要查看会发生什么情况:
fn main() {
let number = 7;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
再次运行该程序,并查看输出:
$ 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
还值得注意的是,此代码中的 condition 必须是bool
.如果
条件不是bool
,我们将收到一个错误。例如,尝试运行
以下代码:
文件名: src/main.rs
fn main() {
let number = 3;
if number {
println!("number was three");
}
}
这if
condition 的计算结果为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
For more information about this error, try `rustc --explain E0308`.
error: could not compile `branches` (bin "branches") due to 1 previous error
该错误表明 Rust 期望bool
但得到一个整数。与
Ruby 和 JavaScript 等语言,Rust 不会自动尝试
将非布尔类型转换为布尔类型。您必须明确并始终提供if
,以 Boolean 作为其条件。如果我们想使用if
要运行的代码块
仅当数字不等于0
,例如,我们可以更改if
expression 设置为以下内容:
文件名: src/main.rs
fn main() { let number = 3; if number != 0 { println!("number was something other than zero"); } }
运行此代码将打印number was something other than zero
.
处理多个条件else if
您可以通过组合使用多个条件if
和else
在else if
表达。例如:
文件名: src/main.rs
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
表达式并执行
条件计算结果为true
.请注意,即使
虽然 6 可以被 2 整除,但我们看不到输出number is divisible by 2
,
我们也看不到number is not divisible by 4, 3, or 2
文本else
块。这是因为 Rust 只执行第一个区块true
condition,一旦找到一个,它甚至不会检查其余的。
使用太多else if
表达式可能会使您的代码变得混乱,因此,如果您有更多
而不是 1,则可能需要重构代码。第 6 章描述了一个强大的
名为match
对于这些情况。
用if
在let
陈述
因为if
是一个表达式,我们可以在let
语句将结果分配给一个变量,如示例 3-2 所示。
fn main() { let condition = true; let number = if condition { 5 } else { 6 }; println!("The value of number is: {number}"); }
if
expression 添加到变量这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
expression 取决于执行的代码块。这意味着
值,这些值有可能成为if
必须是
相同类型;在示例 3-2 中,两个if
arm 和else
手臂i32
整数。如果类型不匹配,如下所示
example,我们将得到一个错误:
文件名: src/main.rs
fn main() {
let condition = true;
let number = if condition { 5 } else { "six" };
println!("The value of number is: {number}");
}
当我们尝试编译此代码时,我们将收到一个错误。这if
和else
武器
具有不兼容的值类型,并且 Rust 会准确指示
在程序中找到问题:
$ 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
For more information about this error, try `rustc --explain E0308`.
error: could not compile `branches` (bin "branches") due to 1 previous error
的if
块的计算结果为整数,而
这else
block 的计算结果为 string。这不起作用,因为变量必须
有一个类型,并且 Rust 需要在编译时知道number
变量是。了解number
让
compiler 验证类型在我们使用的任何地方都有效number
.Rust 不会
如果number
仅在运行时确定;这
编译器会更复杂,并且对代码的保证更少
如果它必须跟踪任何变量的多个假设类型。
使用 Loops 重复
多次执行一个代码块通常很有用。对于此任务, Rust 提供了几个循环,这些循环将遍历循环内的代码 body 到最后,然后立即从头开始。试验 使用 Loops,让我们创建一个名为 Loops 的新项目。
Rust 有三种循环:loop
,while
和for
.让我们逐一尝试。
重复代码loop
这loop
keyword 告诉 Rust 一遍又一遍地执行一段代码
永远或直到您明确告诉它停止。
例如,将 loops 目录中的 src/main.rs 文件更改为 喜欢这个:
文件名: src/main.rs
fn main() {
loop {
println!("again!");
}
}
当我们运行这个程序时,我们会看到again!
一遍又一遍地连续打印
直到我们手动停止程序。大多数终端都支持键盘快捷键 - 中断卡在连续
圈。试一试:ctrlc
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished dev [unoptimized + debuginfo] target(s) in 0.29s
Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!
符号^C
表示您按 - 的位置。你
可能会也可能看不到单词ctrlcagain!
打印在^C
,具体取决于
代码在接收到中断信号时处于循环中。
幸运的是,Rust 还提供了一种使用代码跳出循环的方法。你
可以放置break
关键字来告诉程序何时停止
执行循环。回想一下,我们在第 2 章的“正确猜测后退出”部分的猜谜游戏中这样做了,当用户赢得游戏时退出程序
猜对数字。
我们还使用了continue
在猜谜游戏中,它在循环中告诉程序
跳过此循环迭代中的任何剩余代码,并转到
next 迭代。
从循环返回值
的用途之一loop
是重试您知道可能会失败的作,例如
检查线程是否已完成其作业。您可能还需要将
该作的结果从循环中传出到代码的其余部分。待办事项
这样,您可以在break
表达你
用于停止循环;该值将从循环中返回,因此您可以
使用它,如下所示:
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
保存从
循环。在循环的每次迭代中,我们都会添加1
到counter
变量
然后检查counter
等于10
.当它出现时,我们使用break
keyword 的值为counter * 2
.在循环之后,我们使用
分号结束将值分配给result
.最后,我们
打印result
,在本例中为20
.
您还可以return
从循环内部。而break
仅退出当前
圈return
始终退出当前函数。
Loop 标签以消除多个 Loop 之间的歧义
如果 Loop 中有 Loops,break
和continue
应用于最里面
循环。您可以选择在循环上指定一个循环标签,该标签
然后,您可以将其与break
或continue
以指定这些关键字
应用于带标签的 Loop,而不是最内层的 Loop。循环标签必须开始
替换为单引号。下面是一个包含两个嵌套循环的示例:
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
那
未指定 Label 将仅退出内部循环。这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
程序通常需要评估循环中的条件。虽然
condition 为true
,则循环运行。当条件不再true
这
程序调用break
,停止循环。可以实现行为
就像这样使用loop
,if
,else
和break
;你可以
如果您愿意,现在就在一个程序中尝试一下。然而,这种模式非常普遍
Rust 有一个内置的语言结构,称为while
圈。在
示例 3-3,我们使用while
循环程序 3 次,每次循环倒计时
time,然后在循环后打印一条消息并退出。
fn main() { let mut number = 3; while number != 0 { println!("{number}!"); number -= 1; } println!("LIFTOFF!!!"); }
while
循环,以便在条件为 true 时运行代码此构造消除了大量嵌套,如果您使用loop
,if
,else
和break
,而且情况更清晰。虽然条件
计算结果为true
,则代码运行;否则,它将退出循环。
循环遍历集合for
您还可以使用while
construct 遍历
集合,例如数组。例如,示例 3-4 中的循环打印了每个
元素a
.
fn main() { let a = [10, 20, 30, 40, 50]; let mut index = 0; while index < 5 { println!("the value is: {}", a[index]); index += 1; } }
while
圈在这里,代码通过数组中的元素进行计数。它从索引开始0
,然后循环,直到到达数组中的最终索引(即
什么时候index < 5
不再true
).运行此代码将打印每个
元素中:
$ 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
正如预期的那样,所有 5 个 array 值都显示在终端中。即使index
将达到5
在某些时候,循环在尝试之前停止执行
从数组中获取第六个值。
但是,这种方法容易出错;如果出现以下情况,我们可能导致程序 panic
索引值或测试条件不正确。例如,如果您更改了
的定义a
数组设置为具有四个元素,但忘记更新
condition 设置为while index < 4
,代码将 panic。它也很慢,因为
编译器添加运行时代码以执行条件检查是否
index 在循环的每次迭代中都在数组的边界内。
作为更简洁的替代方法,您可以使用for
循环并执行一些代码
对于集合中的每个项目。一个for
loop 类似于示例 3-5 中的代码。
fn main() { let a = [10, 20, 30, 40, 50]; for element in a { println!("the value is: {element}"); } }
for
圈当我们运行这段代码时,我们将看到与示例 3-4 中相同的输出。更多 重要的是,我们现在提高了代码的安全性,并消除了 因超出数组末尾或不超出数组末尾而可能导致的 bug 的几率 走得足够远,缺少一些项目。
使用for
循环中,如果
您更改了数组中值的数量,就像使用 Method
在示例 3-4 中使用。
安全性和简洁性for
Loop 使它们成为最常用的 Loop
构造。即使在您想要运行某些代码 a
一定次数,例如在使用while
圈
在示例 3-3 中,大多数 Rustacean 会使用for
圈。实现目标的方法
将使用Range
,由标准库提供,该库生成
所有数字按顺序从一个数字开始,在另一个数字之前结束
数。
以下是使用for
loop 和另一种方法
我们还没有讨论过,rev
,要反转范围:
文件名: src/main.rs
fn main() { for number in (1..4).rev() { println!("{number}!"); } println!("LIFTOFF!!!"); }
这段代码好一点,不是吗?
总结
你成功了!这是一个相当大的章节:您了解了变量、标量
和复合数据类型、函数、注释、if
表达式和循环!自
练习本章中讨论的概念,尝试构建程序以
执行以下作:
- 在华氏度和摄氏度之间转换温度。
- 生成第 n个斐波那契数。
- 打印圣诞颂歌“The Twelve Days of Christmas”的歌词。 利用歌曲中的重复。
当你准备好继续时,我们将讨论 Rust 中一个在其他编程语言中通常不存在的概念:所有权。
本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准