当前位置: 首页 > news >正文

rust流程控制

控制流
根据条件是否为真来决定是否执行某段代码,以及在条件为真时反复执行某段代码,是绝大多数编程语言的基本组成模块。在 Rust 中,最常见的控制执行流程的结构是 if 表达式和循环。

if 表达式

if 表达式让你根据条件对代码进行分支。你提供一个条件,然后声明:“如果条件成立,就执行这段代码;如果条件不成立,就不执行这段代码。”

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 开头,后跟一个条件。上例中的条件检查变量 number 的值是否小于 5。在条件后用花括号包裹的代码块是条件为真时要执行的内容。与 if 表达式中条件关联的代码块有时被称为“分支”(arm),类似于第 2 章“猜数游戏”一节中讨论的 match 表达式的分支。

可以选择性地添加 else 表达式(如上例所示),以便在条件为假时执行另一段代码。如果不提供 else,条件为假时程序会直接跳过 if 块,继续执行后面的代码。

运行这段代码,你会看到以下输出:

$ cargo runCompiling branches v0.1.0 (file:///projects/branches)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31sRunning `target/debug/branches`
condition was true

number 的值改成使条件为假的值,看看会发生什么:

let number = 7;

再次运行程序,输出如下:

$ cargo runCompiling branches v0.1.0 (file:///projects/branches)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31sRunning `target/debug/branches`
condition was false

注意:这里的条件必须是 bool 类型。如果条件不是 bool,会得到一个错误。例如,运行以下代码:

文件名:src/main.rs(这段代码无法编译!)

fn main() {let number = 3;if number {println!("number was three");}
}

此时 if 条件的值是整数 3,Rust 会报错:

$ cargo runCompiling 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 的条件。如果想让代码块只在数字不为 0 时运行,可以这样写:

文件名: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 处理多重条件

可以把 ifelse 组合成 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 runCompiling branches v0.1.0 (file:///projects/branches)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31sRunning `target/debug/branches`
number is divisible by 3

程序会依次检查每个 if 表达式,执行第一个条件为真的分支。注意 6 也能被 2 整除,但不会打印 number is divisible by 2,也不会执行 else 块。Rust 一旦找到第一个为真的条件就停止检查其余条件。

过多的 else if 会让代码变得杂乱,如果超过一个,可以考虑用第 6 章介绍的 match 结构来重构。

let 语句中使用 if

因为 if 是表达式,所以可以把它放在 let 语句的右侧,把结果赋值给一个变量,如示例 3-2 所示。

文件名:src/main.rs

fn main() {let condition = true;let number = if condition { 5 } else { 6 };println!("The value of number is: {number}");
}

示例 3-2:把 if 表达式的结果赋给变量

变量 number 将绑定到 if 表达式求值后的结果。运行这段代码:

$ cargo runCompiling branches v0.1.0 (file:///projects/branches)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30sRunning `target/debug/branches`
The value of number is: 5

记住,代码块的值是其最后一个表达式的值,数字本身也是表达式。此时整个 if 表达式的值取决于哪个分支被执行。这意味着每个分支可能返回的值必须是同一类型;在示例 3-2 中,if 分支和 else 分支的结果都是 i32 整数。如果类型不匹配,如下例所示,会得到编译错误:

文件名:src/main.rs(这段代码无法编译!)

fn main() {let condition = true;let number = if condition { 5 } else { "six" };println!("The value of number is: {number}");
}

编译这段代码会报错,ifelse 分支的类型不兼容:

$ cargo runCompiling 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`

if 分支返回整数,else 分支返回字符串,这行不通,因为变量必须有单一类型,而 Rust 在编译时就要确定变量 number 的类型。如果类型只能在运行时确定,编译器将变得更复杂,对代码的保证也会减少。


用循环实现重复

多次执行一段代码往往很有用。Rust 提供了几种循环,它们会从头到尾执行循环体,然后立刻回到开头。为了实验循环,我们新建一个名为 loops 的项目。

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

loop 重复执行

关键字 loop 告诉 Rust 反复执行一段代码,直到你显式让它停止。

loops 目录下的 src/main.rs 改成以下内容:

文件名:src/main.rs

fn main() {loop {println!("again!");}
}

运行后你会看到 again! 不断打印,直到手动停止。大多数终端支持用 ctrl-c 中断陷入无限循环的程序:

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

符号 ^C 表示你按下了 ctrl-c,其后是否出现 again! 取决于中断信号到达时循环的位置。

Rust 也支持用代码跳出循环。在循环体内使用 break 关键字即可停止循环。还记得第 2 章猜数游戏中,当用户猜对数字时我们用 break 退出程序。

我们也在猜数游戏中用过 continue,它让程序跳过本次迭代剩余代码,直接开始下一次迭代。

从循环返回值

有时需要在循环中重试可能失败的操作,例如检查线程是否完成任务,并把结果传递给外部代码。可以在用于停止循环的 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 存放循环返回值。每次迭代 counter 加 1,当等于 10 时用 break counter * 2 返回值。循环后用分号结束赋值语句,最后打印 result 的值 20。

你也可以在循环内使用 returnbreak 仅退出当前循环,return 会立即退出整个函数。

用循环标签消除歧义

如果有嵌套循环,breakcontinue 默认作用于最内层循环。可以给循环加上标签,然后用 breakcontinue 指定作用于哪个标签的循环。标签以单引号开头。以下示例包含两个嵌套循环:

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 runCompiling loops v0.1.0 (file:///projects/loops)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.58sRunning `target/debug/loops`
count = 0
remaining = 10
remaining = 9
count = 1
remaining = 10
remaining = 9
count = 2
remaining = 10
End count = 2

条件循环 while

程序通常需要在循环中评估条件。条件为真时循环运行,条件为假时调用 break 停止循环。虽然可以用 loopifelsebreak 组合实现,但这种模式非常常见,Rust 提供了内置的 while 循环。示例 3-3 中用 while 让程序倒数 3 次,然后打印消息并退出。

文件名:src/main.rs

fn main() {let mut number = 3;while number != 0 {println!("{number}!");number -= 1;}println!("LIFTOFF!!!");
}

示例 3-3:用 while 循环在条件为真时运行代码

这种写法避免了使用 loopifelsebreak 时必须的嵌套,更清晰。条件为真时运行代码,否则退出循环。

for 遍历集合

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

文件名:src/main.rs

fn main() {let a = [10, 20, 30, 40, 50];let mut index = 0;while index < 5 {println!("the value is: {}", a[index]);index += 1;}
}

示例 3-4:用 while 循环遍历集合元素

代码从索引 0 开始,循环到数组最后一个索引。运行后打印:

$ cargo runCompiling loops v0.1.0 (file:///projects/loops)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.32sRunning `target/debug/loops`
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50

然而这种方法容易出错:如果索引或测试条件写错,可能导致 panic。例如,把数组改成 4 个元素却忘了把条件改成 index < 4,就会 panic。此外,每次迭代都要运行时检查索引是否越界,效率较低。

更简洁安全的做法是使用 for 循环,为集合中的每一项执行代码。示例 3-5 展示了 for 循环的写法。

文件名:src/main.rs

fn main() {let a = [10, 20, 30, 40, 50];for element in a {println!("the value is: {element}");}
}

示例 3-5:用 for 循环遍历集合元素

运行后输出与示例 3-4 相同。更重要的是,代码更安全,消除了越界或遗漏元素的可能性。如果数组元素数量改变,无需像示例 3-4 那样修改其他代码。

由于安全与简洁,for 循环是 Rust 中最常用的循环结构。即使像示例 3-3 那样需要固定次数的倒数,大多数 Rustaceans 也会用 for 循环。可以使用标准库提供的 Range 生成连续整数序列,并用 rev 反转范围:

文件名:src/main.rs

fn main() {for number in (1..4).rev() {println!("{number}!");}println!("LIFTOFF!!!");
}

这段代码看起来更简洁吧?


总结

本章内容不少:你学习了变量、标量和复合数据类型、函数、注释、if 表达式和循环!为了巩固本章概念,可以尝试编写以下程序:

  • 实现华氏度与摄氏度的相互转换。
  • 生成第 n 个斐波那契数。
  • 利用歌曲中的重复结构打印圣诞颂歌《圣诞十二日》的歌词。

准备好后,我们将讨论 Rust 中其他语言不常见的概念:所有权。

http://www.dtcms.com/a/296727.html

相关文章:

  • Code Composer Studio:CCS 设置代码折叠
  • 20.OSPF路由协议·单区域
  • 枚举右,维护左高级篇
  • [明道云] -基础入门1- 什么是明道云 HAP 平台?
  • 【基础篇一】Python Web开发的演进历程(CGI → WSGI → ASGI)
  • 100条SQL语句分类精讲:从基础到进阶的实操指南
  • Matplotlib详细教程(基础介绍,参数调整,绘图教程)
  • 支付宝小程序 SEO 优化指南:从流量获取到商业转化
  • 【Linux】常用命令(一)
  • LockscreenCredential 类方法详解
  • 机器学习入门与经典knn算法表文解析
  • 模型的存储、加载和部署
  • 天邑TY1613_S905L3SB_安卓9-高安版和非高安版-线刷固件包
  • SSE与Websocket有什么区别?
  • P1049 [NOIP 2001 普及组] 装箱问题
  • 数据采集分析:从信息洪流中掘金的科学与艺术
  • Linux和Windows基于V4L2和TCP的QT监控
  • 欧姆龙CJ1MPLC配以太网模块,打造上位机、触摸屏、变频器高效通讯生态系统案例
  • 词嵌入维度与多头注意力关系解析
  • C++课设实践项目:C++构建的学籍管理系统
  • 【阿里云-ACP-1】疑难题解析
  • CPU绑核并独占
  • 网络编程之多路复用---mutilio
  • tauri实用教程:阻止除控制台关闭程序外的全部手动关闭
  • 大模型-batch之static batch
  • 基于Matlab图像处理的水果分级系统
  • 【软件与环境】--Visual Studio2022安装教程
  • JMeter压测黑马点评优惠券秒杀的配置及请求爆红问题的解决(详细图解)
  • 在Ubuntu上使用QEMU学习RISC-V程序(2)gdb调试
  • 2025年7月23日 AI 今日头条