Rust 作为一门注重安全与效率的语言,提供了与其他主流语言相似但又有细节差异的流程控制语法,主要包括分支控制 (if-else)和循环控制 (loop、while、for)。本教程将基于 Rust 语言圣经(course.rs) 的内容,带您系统掌握 Rust 流程控制的核心用法。
一、分支控制:根据条件"选择道路"
分支控制的核心是"根据条件判断,执行不同代码块",Rust 中最常用的分支结构是 if-else,且不支持 switch(需用 match 替代,后续进阶内容)。
1.1 基础 if-else:满足条件就执行
if 后面必须跟一个布尔值 (bool),不能像 C/C++ 那样隐式转换(如数字 0 代表 false),这是 Rust 类型安全的体现。
语法格式
rust
if 条件表达式(结果为 bool) {
// 条件为 true 时执行的代码块
} else if 另一个条件表达式(结果为 bool) {
// 上一个条件为 false,当前条件为 true 时执行
} else {
// 所有条件都为 false 时执行(可选)
}
示例:判断数字大小
rust
fn main() {
let score = 85;
if score >= 90 {
println!("成绩优秀");
} else if score >= 70 {
println!("成绩良好");
} else if score >= 60 {
println!("成绩及格");
} else {
println!("成绩不及格");
}
}
// 输出:成绩良好
关键注意点
- 条件必须是 bool 类型 :若写
if score { ... }会编译报错,因为score是i32类型,无法直接作为条件。 - 代码块必须用大括号 :即使代码块只有一行,也不能省略
{}(如if true println!("ok")是错误的),这是 Rust 强制的代码风格,避免歧义。
1.2 if 作为表达式:返回值的"条件运算"
在 Rust 中,if-else 不仅是语句,还可以作为表达式 (能返回一个值),类似其他语言的"三元运算符"(Rust 没有 a ? b : c 语法,用 if-else 替代)。
语法规则
- 所有分支的返回值类型必须一致(否则编译器无法推断最终类型)。
- 表达式的返回值不需要
return,最后一行代码的结果就是返回值(若最后一行加了;,则返回()空类型)。
示例 1:获取两个数的最大值
rust
fn main() {
let a = 10;
let b = 20;
// if-else 作为表达式,返回最大值并赋值给 max
let max = if a > b { a } else { b };
println!("最大值是:{}", max); // 输出:最大值是:20
}
示例 2:错误示范(返回类型不一致)
rust
fn main() {
let flag = true;
// 错误:一个分支返回 i32,另一个返回 &str,类型不匹配
let result = if flag { 100 } else { "hello" };
}
二、循环控制:重复执行的"循环赛道"
循环用于让一段代码重复执行,Rust 提供三种循环结构:loop(无限循环)、while(条件循环)、for(遍历循环),覆盖不同场景的重复需求。
2.1 loop:无限循环,手动"刹车"
loop 是最简单的循环,会无限重复执行代码块 ,必须通过 break 手动终止(否则程序会一直运行),适合"不确定循环次数,满足条件就退出"的场景。
基础用法:用 break 终止循环
rust
fn main() {
let mut count = 0;
loop {
count += 1;
println!("当前计数:{}", count);
// 条件满足时终止循环
if count == 3 {
break; // 退出 loop 循环
}
}
// 输出:
// 当前计数:1
// 当前计数:2
// 当前计数:3
}
进阶用法:loop 作为表达式返回值
loop 也可以作为表达式,在 break 后跟上要返回的值(所有 break 的返回值类型需一致),适合"循环中计算结果,退出时返回"的场景。
rust
fn main() {
let mut sum = 0;
let mut num = 1;
// loop 表达式返回最终的 sum 值
let result = loop {
sum += num;
num += 1;
if num > 5 {
break sum; // 退出循环,返回 sum(此时 sum = 1+2+3+4+5 = 15)
}
};
println!("1到5的和是:{}", result); // 输出:1到5的和是:15
}
2.2 while:条件满足才循环
while 循环会先判断条件表达式 (结果为 bool),若为 true 则执行代码块,否则退出循环,适合"已知循环终止条件,不确定循环次数"的场景。
语法格式
rust
while 条件表达式(结果为 bool) {
// 条件为 true 时执行的代码块
}
示例:遍历数组(不推荐,用 for 更优)
rust
fn main() {
let arr = [10, 20, 30, 40];
let mut index = 0;
while index < arr.len() {
println!("数组元素:{}", arr[index]);
index += 1; // 手动更新索引,避免死循环
}
// 输出:
// 数组元素:10
// 数组元素:20
// 数组元素:30
// 数组元素:40
}
注意点:避免死循环
while true 等价于 loop,也需要用 break 终止,例如:
rust
fn main() {
let mut count = 0;
while true {
count += 1;
if count == 2 {
break;
}
}
}
2.3 for:遍历集合的"最优解"
for 循环是 Rust 中最常用的循环,主要用于遍历迭代器(Iterator)或集合 (如数组、Vec、HashMap 等),无需手动管理索引,安全且简洁(避免索引越界问题)。
核心语法:for 变量 in 迭代器/集合 { ... }
Rust 中,所有"可遍历"的类型都实现了 IntoIterator trait,for 循环会自动将集合转换为迭代器,依次取出元素。
示例 1:遍历数组(推荐用法)
直接遍历数组的元素(无需索引),默认是不可变引用 (不转移所有权),若要获取所有权,需用 into_iter();若要可变引用,需用 iter_mut()。
rust
fn main() {
let arr = [1, 2, 3, 4];
// 1. 不可变引用(默认,不转移所有权,arr 后续可继续使用)
println!("不可变遍历:");
for elem in arr.iter() {
println!("{}", elem); // elem 是 &i32 类型,自动解引用打印
}
// 2. 转移所有权(arr 后续不可使用)
println!("转移所有权遍历:");
let arr2 = [1, 2, 3];
for elem in arr2.into_iter() {
println!("{}", elem); // elem 是 i32 类型
}
// 3. 可变引用(修改数组元素)
println!("可变遍历(修改元素):");
let mut arr3 = [1, 2, 3];
for elem in arr3.iter_mut() {
*elem += 10; // 用 * 解引用,修改原元素
}
println!("修改后数组:{:?}", arr3); // 输出:[11, 12, 13]
}
示例 2:遍历范围(Range 类型)
Rust 提供 a..b(左闭右开,包含 a 不包含 b)和 a..=b(闭区间,包含 a 和 b)两种范围语法,常用于固定次数的循环。
rust
fn main() {
// 1. 左闭右开:遍历 1,2,3,4(不包含 5)
println!("左闭右开范围:");
for num in 1..5 {
println!("{}", num);
}
// 2. 闭区间:遍历 10,11,12(包含 12)
println!("闭区间范围:");
for num in 10..=12 {
println!("{}", num);
}
}
示例 3:遍历 Vec 集合
rust
fn main() {
let fruits = vec!["苹果", "香蕉", "橙子"];
// 遍历 Vec 的不可变引用
for fruit in fruits.iter() {
println!("水果:{}", fruit);
}
// 遍历后 fruits 仍可使用(因为是引用)
println!("集合长度:{}", fruits.len()); // 输出:3
}
2.4 循环控制:break 与 continue
break 和 continue 是循环中的"控制开关",用于灵活调整循环执行:
break:立即终止当前所在的循环(跳出循环体)。continue:跳过当前循环的剩余代码,直接进入下一次循环。
示例:结合 break 和 continue
rust
fn main() {
let mut num = 0;
loop {
num += 1;
// 1. 跳过偶数(不执行后续打印)
if num % 2 == 0 {
continue;
}
println!("当前奇数:{}", num);
// 2. 当数字大于 10 时终止循环
if num > 10 {
break;
}
}
// 输出:
// 当前奇数:1
// 当前奇数:3
// 当前奇数:5
// 当前奇数:7
// 当前奇数:9
// 当前奇数:11
}
三、实战练习:巩固流程控制用法
通过一个简单的"猜数字游戏",综合运用 if-else、loop、break 等知识,加深对流程控制的理解。
游戏规则
- 程序随机生成一个 1-100 之间的整数。
- 用户输入一个数字,程序判断"大了""小了"或"猜对了"。
- 猜对后退出循环,游戏结束。
完整代码
rust
use std::io;
use rand::Rng; // 需要在 Cargo.toml 中添加 rand 依赖
fn main() {
println!("欢迎来到猜数字游戏!");
println!("我已经生成了一个 1-100 之间的数字,快来猜一猜吧~");
// 1. 生成 1-100 之间的随机数
let secret_num = rand::thread_rng().gen_range(1..=100);
// 2. 无限循环,直到猜对
loop {
println!("\n请输入你猜的数字:");
let mut guess = String::new();
// 3. 读取用户输入
io::stdin()
.read_line(&mut guess)
.expect("无法读取输入");
// 4. 将输入的字符串转换为整数(处理无效输入)
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("请输入有效的数字!");
continue; // 无效输入,跳过后续判断,重新循环
}
};
// 5. 用 if-else 判断大小
if guess < secret_num {
println!("你猜的数字太小了!");
} else if guess > secret_num {
println!("你猜的数字太大了!");
} else {
println!("恭喜你,猜对了!答案就是 {}", secret_num);
break; // 猜对了,终止循环
}
}
}
代码说明
- 随机数生成 :依赖
rand库(需在Cargo.toml中添加rand = "0.8"),gen_range(1..=100)生成 1-100 的闭区间随机数。 - 输入处理 :
read_line读取用户输入,parse转换为整数,若转换失败(如输入字母),用match捕获错误并提示,再用continue重新循环。 - 循环终止 :猜对时用
break退出loop,游戏结束。
四、总结:流程控制的核心要点
- 分支控制 :
if-else是唯一的分支结构,条件必须是bool类型,且支持作为表达式返回值(替代三元运算符)。 - 循环控制 :
loop:无限循环,需用break终止,支持返回值。while:条件循环,适合"已知终止条件,未知次数"。for:遍历循环,优先用于集合/迭代器,安全简洁(避免索引越界)。
- 控制开关 :
break终止循环,continue跳过当前轮次。