Rust 控制流
难度:⭐⭐ | 主题:控制流(Control Flow)
1️⃣ 原理层:Rust 控制流核心概念
控制流是表达式,不是语句
Rust 中几乎所有控制流结构都是表达式(返回值),而不是语句:
if表达式可以赋值给变量match表达式返回最后一个表达式的值loop可以通过break value返回值
这使得 Rust 代码更加函数式和声明式。
Match 模式匹配原理
match value {
pattern1 => expression1,
pattern2 => expression2,
_ => default_expression,
}
- 模式(Pattern):可以是字面量、变量、元组、枚举、引用等
- 守卫(Guard):使用
if添加额外条件:pattern if condition => expr - 绑定(Binding):使用
@操作符同时匹配和绑定值
穷尽性检查(Exhaustiveness Checking)
Rust 编译器强制要求 match 表达式必须覆盖所有可能的值:
- 编译时检查,防止逻辑漏洞
_模式作为兜底(catch-all)- 非穷尽的
match会导致编译错误
2️⃣ 实战层:完整代码示例
2.1 if/else 表达式
fn main() {
let number = 6;
// 基本 if
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else {
println!("number is not divisible by 4 or 3");
}
// if 作为表达式
let condition = true;
let result = if condition {
5
} else {
6
};
println!("result: {}", result); // result: 5
// ❌ 错误:分支类型不一致
// let inconsistent = if condition {
// 5
// } else {
// "six" // 编译错误:expected integer, found &str
// };
}
2.2 loop 循环
fn main() {
let mut count = 0;
// 基本 loop
loop {
count += 1;
if count == 3 {
break; // 退出循环
}
}
// loop 返回值
let result = loop {
count += 1;
if count == 10 {
break count * 2; // 返回 20
}
};
println!("loop result: {}", result);
// 带标签的 loop
let mut x = 0;
'outer: loop {
x += 1;
'inner: loop {
if x == 2 {
break 'outer; // 跳出外层循环
}
break 'inner;
}
}
// loop + break with value
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("Final result: {}", result); // 20
}
2.3 while 循环
fn main() {
let mut number = 3;
// 基本 while
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!!!");
// while 遍历数组
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("value: {}", a[index]);
index += 1;
}
}
2.4 for 循环
fn main() {
// for 遍历范围
for number in 1..4 {
println!("{}!", number);
}
println!("LIFTOFF!!!");
// for 遍历数组
let a = [10, 20, 30, 40, 50];
for element in a {
println!("value: {}", element);
}
// for 反向遍历
for number in (1..4).rev() {
println!("{}!", number);
}
// for 带索引
for (index, value) in a.iter().enumerate() {
println!("index: {}, value: {}", index, value);
}
// for 遍历字符串
for c in "Hello".chars() {
println!("{}", c);
}
// for 遍历字节
for b in "Hello".bytes() {
println!("{}", b);
}
}
2.5 match 表达式
fn main() {
// 基本 match
let x = 5;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("something else"), // 兜底
}
// match 返回值
let x = 5;
let y = match x {
1 => "one",
2 => "two",
3 => "three",
_ => "other",
};
println!("y = {}", y);
// match 元组
let point = (3, 4);
match point {
(0, 0) => println!("Origin"),
(0, y) => println!("On y-axis at {}", y),
(x, 0) => println!("On x-axis at {}", x),
(x, y) => println!("On ({}, {})", x, y),
}
// match 枚举
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
// match 守卫
let num = Some(4);
match num {
Some(x) if x % 2 == 0 => println!("Even number: {}", x),
Some(x) => println!("Odd number: {}", x),
None => println!("No number"),
}
// @ 绑定
let name = Some(String::from("Alice"));
match name {
Some(ref n @ String::from("Alice")) => println!("Hello {}", n),
Some(n) => println!("Hello {}", n),
None => println!("No name"),
}
}
2.6 if let 表达式
fn main() {
// if let 简化 match
let some_u8_value = Some(0u8);
// 等价于:
// match some_u8_value {
// Some(3) => println!("three"),
// _ => (),
// }
if let Some(3) = some_u8_value {
println!("three");
}
// if let else
let config_max = Some(3u8);
let mut max = 0u8;
if let Some(max_val) = config_max {
max = max_val;
} else {
max = 10;
}
println!("max: {}", max);
// if let 多个模式(Rust 1.53+)
let x = 4;
if let 1 | 2 | 3 = x {
println!("one, two, or three");
}
// while let
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("{}", top);
}
// for 与 if let 结合
let pairs = vec![(1, 2), (3, 4), (5, 6)];
for (x, y) in pairs {
if let (1, _) = (x, y) {
println!("First is 1");
}
}
}
3️⃣ 最佳实践
3.1 选择合适的控制流结构
| 场景 | 推荐结构 |
|---|---|
| 已知迭代次数 | for 循环 |
| 条件未知的循环 | while 循环 |
| 无限循环 | loop + break |
| 模式匹配 | match |
| 单模式匹配 | if let |
| 值的条件分支 | if/else |
3.2 避免无限循环
// ❌ 危险:可能无限循环
loop {
// 没有 break 条件
}
// ✅ 安全:有明确退出条件
loop {
if condition {
break;
}
}
// ✅ 使用 while 更清晰
while !condition {
// ...
}
3.3 match vs if let 选择
使用 match:
- 需要匹配多个模式
- 需要穷尽性检查
- 所有分支都重要
match option {
Some(value) => handle(value),
None => handle_none(),
}
使用 if let:
- 只关心一个模式
- 其他情况不需要处理或统一处理
- 代码更简洁
if let Some(value) = option {
handle(value);
}
// 其他情况忽略
3.4 表达式风格
优先使用表达式风格,使代码更函数式:
// ✅ 表达式风格
let status = if score > 60 { "pass" } else { "fail" };
// ❌ 语句风格(冗余)
let status;
if score > 60 {
status = "pass";
} else {
status = "fail";
}
4️⃣ 问题诊断
4.1 编译错误:类型不匹配
// ❌ 错误
let x = if true {
5
} else {
"five" // error: if and else have incompatible types
};
// ✅ 修复:统一类型
let x = if true {
5
} else {
0
};
4.2 非穷尽 match
// ❌ 错误
enum Direction {
Up,
Down,
Left,
Right,
}
fn move_player(dir: Direction) {
match dir {
Direction::Up => println!("Up"),
Direction::Down => println!("Down"),
// error: non-exhaustive patterns: `Left` and `Right` not covered
}
}
// ✅ 修复 1:覆盖所有模式
fn move_player_fixed(dir: Direction) {
match dir {
Direction::Up => println!("Up"),
Direction::Down => println!("Down"),
Direction::Left => println!("Left"),
Direction::Right => println!("Right"),
}
}
// ✅ 修复 2:使用 _ 兜底
fn move_player_default(dir: Direction) {
match dir {
Direction::Up => println!("Up"),
Direction::Down => println!("Down"),
_ => println!("Other direction"),
}
}
4.3 无限循环警告
// ⚠️ 警告:denying some lints due to unknown or unstable features
#[warn(unconditional_recursion)]
fn recurse() {
recurse(); // warning: function cannot return
}
// ✅ 修复:添加终止条件
fn recurse_fixed(n: u32) {
if n > 0 {
recurse_fixed(n - 1);
}
}
4.4 if let 与变量遮蔽
// ⚠️ 注意:内部变量遮蔽外部变量
let x = 5;
if let Some(x) = Some(10) {
println!("{}", x); // 10,不是 5
}
println!("{}", x); // 5
// ✅ 明确命名避免混淆
let original_x = 5;
if let Some(new_x) = Some(10) {
println!("{}", new_x);
}
5️⃣ 权威引用
-
The Rust Book 第 3 章 - Common Programming Concepts
- 3.3 - Functions
- 3.5 - Control Flow
-
The Rust Book 第 6 章 - Enums and Pattern Matching
- 6.2 - The match Control Flow Operator
- 6.3 - Concise Control Flow with if let
-
The Rust Book 第 18 章 - Patterns and Matching
- 18.1 - All the Places Patterns Can Be Used
- 18.2 - Refutability: Whether a Pattern Might Fail to Match
- 18.3 - Pattern Syntax
-
Rust by Example - Flow Control
🎯 学习要点总结
- ✅ 控制流结构在 Rust 中都是表达式(返回值)
- ✅
match提供强大的模式匹配和编译时穷尽性检查 - ✅
if let是处理单模式的简洁语法 - ✅ 选择合适的控制流结构提高代码可读性
- ✅ 注意类型一致性和模式穷尽性
📝 练习题
基础练习
-
FizzBuzz:使用
for循环打印 1-100,3 的倍数打印 Fizz,5 的倍数打印 Buzz,同时是 3 和 5 的倍数打印 FizzBuzz -
成绩等级:使用
match将分数转换为等级(90-100: A, 80-89: B, 70-79: C, 60-69: D, <60: F)
进阶练习
-
斐波那契数列:使用
loop生成前 20 个斐波那契数 -
选项处理器:使用
if let和while let处理Option链 -
自定义枚举匹配:定义一个
TrafficLight枚举,使用match处理不同颜色的行为