📝 本文首发于 栏轩·阁
欢迎访问阅读原文,获取更好的阅读体验。
上一篇我们搞定了变量、数据类型和函数,这一篇进入程序逻辑的核心------控制流 。Rust 的控制流语句有一个贯穿始终的特点:它们几乎都是表达式,能返回值。这一点和 C/Java 等语言差异很大,值得单独写一篇理清楚。
本文所有代码均已实测通过,运行输出贴在对应小节末尾。
1. if 表达式
1.1 基本用法
rust
let n = 7;
if n > 5 {
println!("{n} 大于5");
} else {
println!("{n} 小于等于5");
}
条件必须是 bool 类型 ,Rust 不会像 C 那样把 0 当 false、把非零当 true:
rust
// if 1 { } // ❌ 编译错误:expected `bool`, found integer
这个设计排除了 C 系语言中一大类隐式类型转换导致的 bug。
1.2 if 是表达式,可以赋值
Rust 的 if 整体是一个表达式,可以直接赋值给变量------不需要 C 语言的三元运算符 ?::
rust
let result = if n > 5 { "大于5" } else { "小于等于5" };
每个分支的返回值类型必须一致,否则编译不过:
rust
// let x = if true { 1 } else { "hello" }; // ❌ 类型不匹配
1.3 多分支
rust
let grade = if n >= 9 {
'A'
} else if n >= 7 {
'B'
} else if n >= 5 {
'C'
} else {
'D'
};
运行输出:
7 大于5
分数 7 -> 等级 B
2. loop 无限循环
loop 会一直循环,直到遇到 break。它最独特的能力是 break 可以带一个返回值,这个值就是整个 loop 表达式的结果:
rust
let mut count = 0;
let result = loop {
count += 1;
if count == 5 {
break count * 2; // loop 返回 10
}
};
println!("loop 循环了 {count} 次,返回 {result}");
这种写法在需要「重复尝试直到成功,然后取出结果」的场景下非常自然------比如重试网络请求、等待某个条件满足。
运行输出:
loop 循环了 5 次,返回 10
3. while 条件循环
和大多数语言一样,条件为真时执行循环体。Rust 的 while 没有额外的语法糖:
rust
let mut n = 3;
while n > 0 {
println!("{n}...");
n -= 1;
}
println!("发射!");
运行输出:
倒计时: 3... 2... 1... 发射!
4. for 遍历
for 是 Rust 中最常用的循环------安全、简洁,不存在数组越界的风险。
4.1 遍历数组
rust
let arr = [10, 20, 30, 40, 50];
for elem in arr {
println!("{elem}");
}
这里 elem 是数组元素的副本(标量类型实现了 Copy)。对复杂类型,用 for elem in &arr 可以借用而不转移所有权------这一点后面所有权章节会详细展开。
4.2 Range:灵活的整数序列
rust
// 0..5 不含 5 → 0, 1, 2, 3, 4
for i in 0..5 { }
// 0..=5 包含 5 → 0, 1, 2, 3, 4, 5
for i in 0..=5 { }
// 反向
for i in (1..=5).rev() { } // 5, 4, 3, 2, 1
Rust 没有 C 风格的三段式 for (int i = 0; i < n; i++),Range 替代了这个角色,而且更安全------不会写错终止条件。
运行输出:
数组元素: 10 20 30 40 50
0..5: 0 1 2 3 4
0..=5: 0 1 2 3 4 5
反向: 5 4 3 2 1
5. match 模式匹配
match 是 Rust 控制流的「王牌」------比 C 的 switch 强大得多。
5.1 基本匹配
rust
let num = 3;
match num {
1 => println!("一"),
2 => println!("二"),
3 => println!("三"),
_ => println!("其他"),
}
几个关键点:
_是通配符 ,匹配所有未被前面分支覆盖的值。如果去掉_分支,编译器会报错------因为num可能是 4、5、100......match不会「穿透」(fall-through),匹配到一个分支就停,不需要break
5.2 match 也是表达式
和 if、loop 一样,match 整体可以返回值:
rust
let desc = match num {
1 => "最小",
2 | 3 | 5 | 7 => "质数", // | 表示「或」
4 | 6 | 8 | 9 | 10 => "合数",
_ => "超出范围",
};
5.3 穷尽性检查------Rust 的安全底线
match 最强大的设计是编译器强制你处理所有可能的情况。如果漏了一个分支:
rust
// match num {
// 1 => "一",
// 2 => "二",
// } // ❌ 编译错误:non-exhaustive patterns
编译器会直接拒绝编译,并提示你哪些值没被覆盖。这意味着 match 本质上是编译期安全网 ------只要你用了 match 而不是 if-else,就永远不会漏掉边界情况。
运行输出:
三
7 是质数
6. 五种控制流对比
| 语句 | 是否表达式 | 典型用途 |
|---|---|---|
if |
是 | 条件判断、分支赋值 |
loop |
是 | 无限循环、重试逻辑、break 返回值 |
while |
否 | 条件驱动的循环 |
for |
否 | 遍历集合、Range |
match |
是 | 穷举匹配、编译器安全保障 |
总结
这一篇覆盖了 Rust 五种控制流:
if是表达式 ------不需要三元运算符,分支返回值类型必须一致,条件必须是boolloop------break可以带返回值,适合「循环直到成功」的场景while------和主流语言一致,没有额外概念for------配合 Range 替代 C 风格三段式 for,安全且直观match------穷尽性检查是编译期的安全网,_是通配符,|表示或
下一篇即将进入 Rust 的「灵魂」------所有权、借用与生命周期。这是整个学习过程中最重要、也是最需要时间消化的一篇。