Rust 控制流
文章目录
- Rust 控制流
- `if` 表达式
- 循环实现重复
- 用 `loop` 重复代码
- 从循环返回值
- 循环标签用于区分多层循环
- while 条件循环
- 用 `for` 循环遍历集合
Rust 控制流
在大多数编程语言中,根据条件是否为真来运行某些代码,以及在条件为真时重复运行某些代码,是最基本的构建块。Rust 中最常见的控制代码执行流程的结构是 if
表达式和循环。
if
表达式
if
表达式允许你根据条件分支代码。你提供一个条件,然后说明:“如果满足这个条件,就运行这段代码块。如果不满足,就不运行。”
在你的项目目录下新建一个名为 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。如果条件为真,则立即执行大括号内的代码块。与 match
表达式类似,if
表达式中与条件相关联的代码块有时也被称为“分支”。
你还可以选择包含 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
需要注意的是,if
的条件必须是 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
提供布尔条件。例如,如果只想在 number
不等于 0 时运行 if
代码块,可以这样写:
文件名: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
处理多个条件
你可以通过 else if
组合 if
和 else
来处理多个条件。例如:
文件名: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,因为 Rust 只会执行第一个为真的分支,之后的不会再检查。
如果 else if
太多,代码会变得混乱。此时可以考虑用 Rust 更强大的分支结构 match
(第 6 章会介绍)。
在 let
语句中使用 if
因为 if 是表达式,可以用在 let 语句右侧,将结果赋值给变量,如下例所示:
文件名:src/main.rs
fn main() {let condition = true;let number = if condition { 5 } else { 6 };println!("The value of number is: {number}");
}
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
表达式的值取决于哪个分支被执行。if
和 else
的返回值类型必须一致;如果类型不一致,会报错:
文件名:src/main.rs
此代码无法编译!
fn main() {let condition = true;let number = if condition { 5 } else { "six" };println!("The value of number is: {number}");
}
编译时会报错,提示类型不兼容:
$ 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`| || expected because of this
if
分支返回整数,else
分支返回字符串。Rust 需要在编译时确定变量类型,不能在运行时才决定。
循环实现重复
有时需要多次执行一段代码。为此,Rust 提供了多种循环结构,会不断执行循环体中的代码。让我们新建一个名为 loops 的项目来实验循环。
Rust 有三种循环:loop
、while
和 for
。下面分别介绍。
用 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
。你可能会看到 ^C 后还有 again!,这取决于中断时循环执行到哪。
幸运的是,Rust 也允许你用 break
关键字跳出循环。你可以在循环中用 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)。
你也可以在循环中用 return
直接返回,return
会退出当前函数,而 break 只退出当前循环。
循环标签用于区分多层循环
如果循环嵌套,break
和 continue
默认作用于最内层循环。你可以为循环加标签(以单引号开头),用 break
或 continue
指定作用于哪个循环。例如:
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 退出。虽然可以用 loop
、if
、else
和 break
实现,但这种模式很常见,Rust 提供了 while 循环。如下例,使用 while
循环倒计时三次,循环结束后打印消息并退出。
文件名:src/main.rs
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
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 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
虽然能正常输出,但这种写法容易出错。如果数组 a 改为 4 个元素,却忘了把条件改为 while index < 4
,程序会 panic。而且每次循环都要检查索引是否越界,效率较低。
更简洁安全的做法是用 for 循环遍历集合,如下所示:
文件名:src/main.rs
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
fn main() {for number in (1..4).rev() {println!("{number}!");}println!("LIFTOFF!!!");
}
这样写更优雅。
相关文章:

Rust 控制流
文章目录 Rust 控制流if 表达式循环实现重复用 loop 重复代码从循环返回值循环标签用于区分多层循环while 条件循环用 for 循环遍历集合 Rust 控制流 在大多数编程语言中,根据条件是否为真来运行某些代码,以及在条件为真时重复运行某些代码,是…...
【Linux基础知识系列】第十三篇-Cron与定时任务管理
在Linux系统中,任务自动化是提高效率和确保服务连续性的关键。Cron是一个强大的定时任务管理工具,它允许用户设置定期执行的命令或脚本。通过Cron,用户可以自动化系统维护、备份、报告生成等多种任务。本文将详细介绍如何使用Cron工具创建和管…...
Visual Studio 中的 MD、MTD、MDD、MT 选项详解
在Visual Studio中开发C++项目时,正确选择运行时库(runtime library)对于确保应用程序的性能、稳定性和兼容性至关重要。本文将详细介绍/MD, /MT, /MDd, 和 /MTd这些编译器选项的意义、应用场景及其区别。 MSVCRT.dll MSVCRT.dll 是 Microsoft Visual C++ Runtime Library …...

Python 3.11.9 安装教程
前言 记录一下Windows环境下Python解释器的安装过程。 安装过程 1、安装程序下载 打开Python官网: 点击Downloads,选择Windows: 页面中找到需要的3.11.9版本,点击Download Windows installer (64-bit)下载: 2、…...

【各种主流消息队列(MQ)对比指南】
主流消息队列对比分析 一、核心指标对比 特性/消息队列RabbitMQKafkaRocketMQActiveMQPulsar协议支持AMQP, MQTT, STOMP自定义协议JMS/自定义协议JMS, AMQP, MQTT, STOMPMQTT, AMQP, STOMP单机吞吐量万级百万级十万级万级百万级延迟微秒级(低吞吐)毫秒…...

PySpark、Plotly全球重大地震数据挖掘交互式分析及动态可视化研究
全文链接:https://tecdat.cn/?p42455 分析师:Yapeng Zhao 在数字化防灾减灾的时代背景下,地震数据的深度解析成为公共安全领域的关键议题。作为数据科学工作者,我们始终致力于通过技术整合提升灾害数据的应用价值(点击…...
代码训练LeetCode(24)数组乘积
代码训练(24)LeetCode之数组乘积 Author: Once Day Date: 2025年6月5日 漫漫长路,才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 238. 除自身以外数组的乘积 - 力扣(LeetCode)力扣 (LeetCode) 全…...

如何让AI自己检查全文?使用OCR和LLM实现自动“全文校订”(可DIY校订规则)
详细流程及描述参见仓库(如果有用的话,请给个收藏): GitHub - xurongtang/DocRevision_Proj: A simple project about how to revist docment (such as your academic paper) in a automatic way with the help of OCR and LLM.A…...
volka 25个短语动词
以下是分句分段后的内容: 3,000. Thats 95% of spoken English. And I am teaching you all of these words. First, Ill teach you todays words. And then youll hear them in real conversations. With my brother. Stick around until the end, because witho…...
Java观察者模式深度解析:构建松耦合事件驱动系统的艺术
目录 观察者模式基础解析核心结构与实现原理Java内置观察者实现Spring框架中的高级应用典型应用场景与实战案例观察者模式变体与优化常见问题与最佳实践总结与未来展望1. 观察者模式基础解析 1.1 模式定义与核心思想 观察者模式(Observer Pattern)是一种行为型设计模式,它…...

DFT测试之TAP/SIB/TDR
TAP的作用 tap全称是test access port,是将jtag接口转为reset、sel、ce、ue、se、si、tck和so这一系列测试组件接口的模块。 jtag的接口主要是下面几个信号: 信号名称信号方向信号描述TCK(测试时钟)输入测试时钟,同…...

【推荐算法】DeepFM:特征交叉建模的革命性架构
DeepFM:特征交叉建模的革命性架构 一、算法背景知识:特征交叉的演进困境1.1 特征交叉的核心价值1.2 传统方法的局限性 二、算法理论/结构:双路并行架构2.1 FM组件:显式特征交叉专家2.2 Deep组件:隐式高阶交叉挖掘机2.3…...
C#报错 iText.Kernel.Exceptions.PdfException: ‘Unknown PdfException
【问题】 直接new一个PdfWriter的对象直接会报错: iText.Kernel.Exceptions.PdfException: Unknown PdfException. NotSupportedException: Either com.itextpdf:bouncy-castle-adapter or com.itextpdf:bouncy-castle-fips-adapter dependency must be added in…...

数据库表中「不是 null」的含义
例图: 1.勾选了「不是 null」(NOT NULL): 这个字段在数据库中必须有值,不能为空。也就是说,你插入数据的时候,必须给它赋值,否则插入会报错。 2.没有勾选「不是 null」ÿ…...
Elasticsearch的搜索流程描述
Elasticsearch 的搜索流程是一个结合 分布式查询、分片协同、结果聚合和排序 的复杂过程,其设计目标是在海量数据中实现快速检索和精准结果返回。以下是搜索流程的详细解析: 一、搜索流程总览 Elasticsearch 搜索流程示意图 (图源:Elastic 官方文档) 二、详细步骤解析 …...

Visual Studio问题记录
程序"xxx dotnet.exe"已退出,返回值为-2147450730 问deepseek:visual studio输出程序dotnet.exe已退出,返回值为-2147450730 dotnet.exe 编译时退出并返回错误代码 **-2147450730**(十六进制 0x80008076)&…...
GNSS终端授时方式-合集:PPS、B码、NTP、PTP、单站授时,共视授时
GNSS接收机具备授时功能,能够对外输出高精度的时间信息,并通过多种接口、多种形式进行时间信息的传递。 step by step介绍GNSS卫星导航定位基本原理,为什么定位需要至少4个卫星?这个文章的最后,我们介绍了为什么GNSS接…...
5.2 HarmonyOS NEXT应用性能诊断与优化:工具链、启动速度与功耗管理实战
HarmonyOS NEXT应用性能诊断与优化:工具链、启动速度与功耗管理实战 在HarmonyOS NEXT的全场景生态中,应用性能直接影响用户体验。通过专业的性能分析工具链、针对性的启动速度优化,以及精细化的功耗管理,开发者能够构建"秒…...
从EDR到XDR:终端安全防御体系演进实践指南
在数字化浪潮中,企业的终端安全面临着前所未有的挑战。从早期单纯的病毒威胁,到如今复杂多变的高级持续性威胁(APT)、零日漏洞攻击等,安全形势日益严峻。为应对这些挑战,终端安全防御技术不断演进ÿ…...

重启路由器ip不变怎么回事?原因分析与解决方法
在日常生活中,我们经常会遇到网络问题,而重启路由器是解决网络故障的常用方法之一。然而,有些用户发现,即使重启了路由器,自己的IP地址却没有变化,这让他们感到困惑。那么,重启路由器IP不变是怎…...

实践篇:利用ragas在自己RAG上实现LLM评估②
文章目录 使用ragas做评估在自己的数据集上评估完整代码代码讲解1. RAG系统构建核心组件初始化文档处理流程 2. 评估数据集构建3. RAGAS评估实现1. 评估数据集创建2. 评估器配置3. 执行评估 本系列阅读: 理论篇:RAG评估指标,检索指标与生成指…...
【CVE-2025-4123】Grafana完整分析SSRF和从xss到帐户接管
摘要 当Web应用程序使用URL参数并将用户重定向到指定的URL而不对其进行验证时,就会发生开放重定向。 /redirect?url=https://evil.com`–>(302重定向)–>`https://evil.com这本身可能看起来并不危险,但这种类型的错误是发现两个独立漏洞的起点:全读SSRF和帐户接管…...

高精度滚珠导轨在医疗设备中的多元应用场景
在医疗行业不断追求高效、精准与安全的今天,医疗设备的性能优化至关重要。每一个精密部件都像是设备这个庞大“生命体”中的细胞,共同维持着设备的稳定运行。滚珠导轨,这一看似不起眼却功能强大的传动元件,正悄然在医疗设备领域发…...
深入理解Java单例模式:确保类只有一个实例
文章目录 什么是单例模式?为什么我们需要单例模式?单例模式的常见实现方式1. 饿汉式(Eager Initialization)2. 懒汉式(Lazy Initialization)3. 双重检查锁定(Double-Checked Locking - DCL&…...

JavaScript性能优化实战:从核心原理到工程实践的全流程解析
下面我给出一个较为系统和深入的解析,帮助你理解和实践“JavaScript 性能优化实战:从核心原理到工程实践的全流程解析”。下面的内容不仅解释了底层原理,也结合实际工程中的最佳模式和工具,帮助你在项目中贯彻性能优化理念&#x…...

【应用】Ghost Dance:利用惯性动捕构建虚拟舞伴
Ghost Dance是葡萄牙大学的一个研究项目,研究方向是探索人与人之间的联系,以及如何通过虚拟舞伴重现这种联系。项目负责人Cecilia和Rui利用惯性动捕创造出具有流畅动作的虚拟舞伴,让现实中的舞者也能与之共舞。 挑战:Ghost Danc…...

使用 Mechanical 脚本获取联合反作用力和力矩
介绍 在上一篇文章中,我们详细介绍了在 Ansys Mechanical 静态/瞬态结构、随机振动和/或响应谱分析中提取所有螺栓连接的反作用力的过程。他,我们将讨论如何使用 Python 代码结果对象对关节连接执行相同的作,这对于随机振动/响应谱分析非常有…...
Java垃圾回收机制详解:从原理到实践
Java垃圾回收机制详解:从原理到实践 前言 垃圾回收(Garbage Collection,简称GC)是Java虚拟机自动管理内存的核心机制之一。它负责自动识别和回收不再被程序使用的内存空间,从而避免内存泄漏和溢出问题。深入理解垃圾…...
thinkphp8.1 调用巨量广告API接口,刷新token
1、在mysql中建立表sys_token; CREATE TABLE sys_token (id int UNSIGNED NOT NULL,access_token varchar(50) COLLATE utf8mb4_general_ci NOT NULL,expires_in datetime NOT NULL,refresh_token varchar(50) COLLATE utf8mb4_general_ci NOT NULL,refresh_token_expires_in …...
物联网数据归档方案选择分析
最近在做数据统计分析。我在做数据分析时候,需要设计归档表。有两种方式, 方式1:年月日。 其中,日表是每小时数据,每台设备有24条数据 月表是每天数据,每台设备根据实际月天数插入 年表是每月数据,每台设备有12条数据。 方式2:年月日时。 其中,小时表,是每个设备每小…...