
程序界的"如果...就...":让你的代码学会做决定
想象一下,你早上起床后要做一系列决定:
看,你的一天就是由各种"条件判断"和"循环"组成的!编程也是一样。
在 Rust 里,流程控制就是你的代码学会"思考"和"重复做事"的能力。今天咱们就来聊聊 Rust 是怎么做决定的。
剧透预警:Rust 的 if 居然是个表达式,不是语句!这意味着它可以返回值。是不是很反直觉?别慌,看完这篇你就明白了。
Rust 的条件判断和其他语言长得差不多,但有个关键区别:
// Rust 的 if 是表达式,可以返回值!
let result = if condition { } else { };
生活化类比:
Rust 有三种循环方式,各有各的用处:
循环类型 | 用途 | 生活类比 |
|---|---|---|
loop | 无限循环,直到手动停止 | 跑步机:你不按停止,它就一直转 |
while | 条件循环,条件为真时继续 | 吃自助餐:只要还能吃,就继续拿 |
for | 迭代循环,遍历集合 | 点名:把名单上的名字一个个念出来 |
当你只关心"匹配成功"的情况时,if let 让你少写一堆代码。就像你只关心"快递到了",不关心"快递没到"时该干嘛。
fn main() {
let temperature = ;
// 基础 if/else
if temperature > {
println!("热成狗了,开空调!");
} else if temperature < {
println!("冻成冰棍了,穿秋裤!");
} else {
println!("温度刚刚好,出去浪!");
}
}
逐行解释:
let temperature = 25; — 定义温度变量if temperature > 30 — 如果温度大于 30else if — 否则如果(可以链式调用)else — 以上都不满足时的默认情况注意:Rust 的条件不需要括号!if (x > 0) 是错误的,应该是 if x > 0。编译器会告诉你:
error: expected `{`, found `>`
--> src/main.rs:4:18
|
4 | if (temperature > 30) {
| ^ expected `{`
人话翻译:大哥,Rust 的 if 后面不需要括号,直接跟条件就行!
fn main() {
let number = ;
// if 是表达式,可以返回值!
let description = if number % == {
"偶数"// 这个值会被返回
} else {
"奇数"// 这个值也会被返回
};
println!("{} 是 {}", number, description);
// 输出:7 是 奇数
// 甚至可以嵌套使用
let result = if number > {
if number % == {
"大于 5 的偶数"
} else {
"大于 5 的奇数"
}
} else {
"小于等于 5"
};
println!("{}", result);
}
关键点:
return 关键字fn main() {
let config_max = Some(3u8);
// 传统写法:match 匹配所有情况
match config_max {
Some(max) => println!("最大值是:{}", max),
_ => (), // 其他情况啥也不干
}
// 简洁写法:if let 只关心匹配成功的情况
if let Some(max) = config_max {
println!("最大值是:{}", max);
}
// 其他情况自动忽略,不用写 _ => ()
// 还可以加 else
let coin = Some("heads");
if let Some(side) = coin {
println!("正面:{}", side);
} else {
println!("反面或者没有硬币");
}
}
使用场景:
fn main() {
let mut counter = ;
// loop 会一直循环,直到遇到 break
let result = loop {
counter += ;
if counter == {
break counter * ; // 可以带返回值!
}
};
println!("循环结束,result = {}", result);
// 输出:循环结束,result = 20
}
特点:
loop 是无限循环,必须用 break 退出break 可以返回值,这是 Rust 独有的特性新手坑:忘记写 break,程序变成死循环!
fn main() {
loop {
println!("我要打印一万年...");
// 忘记写 break 了!
// 按 Ctrl+C 强制终止吧...
}
}
fn main() {
let mut number = ;
// 当条件为真时,一直循环
while number > {
println!("{}!", number);
number -= ;
}
println!("发射!🚀");
// 输出:
// 3!
// 2!
// 1!
// 发射!🚀
// while 也可以遍历(但不推荐)
let mut arr = [, , , , ];
let mut index = ;
while index < arr.len() {
println!("arr[{}] = {}", index, arr[index]);
index += ;
}
}
vs for 循环:
while 需要手动管理计数器,容易出错for 更简洁、更安全(后面会讲)fn main() {
// 遍历数组
let arr = [, , , , ];
for element in arr.iter() {
println!("元素:{}", element);
}
// 遍历范围(超好用!)
for number in .. {
println!("计数:{}", number);
// 输出:1, 2, 3(不包含 4!)
}
// 包含终点的范围
for number in ..= {
println!("包含终点:{}", number);
// 输出:1, 2, 3, 4
}
// 反向遍历
for number in (..).rev() {
println!("倒数:{}", number);
// 输出:3, 2, 1
}
}
范围语法:
1..4 — 左闭右开,包含 1 不包含 4(类似 Python)1..=4 — 左右都闭,包含 1 和 4.rev() — 反向迭代器新手坑:忘记 iter() 导致所有权被移动!
fn main() {
let arr = [, , ];
// ❌ 错误:arr 的所有权被移动了
for element in arr {
println!("{}", element);
}
// println!("{:?}", arr); // 编译错误!arr 不能用了
// ✅ 正确:使用 iter() 借用
for element in arr.iter() {
println!("{}", element);
}
// arr 还可以继续使用
println!("{:?}", arr);
}
fn main() {
// 给循环加标签,可以从外层循环 break
'counting_up: for i in ..= {
for j in ..= {
if j == {
// 从外层循环 break
break 'counting_up;
}
println!("i = {}, j = {}", i, j);
}
}
// 输出:
// i = 1, j = 1
// (j=2 时直接跳出外层循环)
}
使用场景:嵌套循环时需要从内层跳出外层
fn main() {
let number = ;
// ❌ 错误:if 和 else 返回不同类型
let description = if number % == {
"偶数"// &str 类型
} else {
// i32 类型!编译器会炸
};
}
编译器错误:
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:7:9
|
4 | let description = if number % 2 == 0 {
| _______________________-
5 | | "偶数"
| | ------ expected because of this
6 | | } else {
7 | | 0
| | ^ expected `&str`, found integer
| |_________|
|
人话翻译:if 和 else 必须返回相同类型!你不能一边返回字符串,一边返回数字。
修复:
let description = if number % == {
"偶数"
} else {
"奇数"// 统一返回 &str
};
fn main() {
let x = ;
// ❌ 错误:if 表达式后面多了一个分号
let y = if x > {
x + ; // 这个分号让返回值变成了 ()
} else {
x -
};
// y 的类型变成了 (),不是你想要的!
}
编译器错误:
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:6:9
|
4 | let y = if x > 3 {
| _____________-
5 | | x + 1;
| | - help: remove this semicolon
| |______________|
| expected integer, found `()`
人话翻译:花括号里最后一个表达式后面的分号会把它变成 () 类型。去掉分号!
fn main() {
let mut i = ;
// ❌ 错误:忘记更新 i,死循环!
while i < {
println!("i = {}", i);
// i += 1; // 忘记写了!
}
// 程序会一直打印 i = 0...
}
最佳实践:能用 for 就别用 while
// ✅ 更好:用 for 循环
for i in .. {
println!("i = {}", i);
}
fn main() {
let mut numbers = vec![, , , , ];
// ❌ 错误:在遍历时修改集合
for num in numbers.iter_mut() {
*num += ;
numbers.push(*num); // 编译错误!
}
}
编译器错误:
error[E0502]: cannot borrow `numbers` as mutable because it is also borrowed as immutable
--> src/main.rs:6:9
|
4 | for num in numbers.iter_mut() {
| ------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
5 | *num += 1;
6 | numbers.push(*num);
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
人话翻译:你正在遍历 numbers,同时又想修改它。Rust 不允许这样做,会出问题的!
修复:
// ✅ 正确:先收集要添加的元素
let mut numbers = vec![, , , , ];
let to_add: Vec<i32> = numbers.iter().map(|&n| n + ).collect();
numbers.extend(to_add);
use std::cmp::Ordering;
fn main() {
let secret_number = ;
let mut attempts = ;
let max_attempts = ;
// 使用 loop 无限循环,直到猜对或次数用完
loop {
attempts += ;
// 检查是否超过最大尝试次数
if attempts > max_attempts {
println!("游戏结束!你输了。正确答案是:{}", secret_number);
break;
}
// 模拟用户输入(实际游戏中用 input 获取)
let guess = + attempts * ;
println!("第 {} 次猜测:{}", attempts, guess);
// 使用 match 比较大小
match guess.cmp(&secret_number) {
Ordering::Less => println!("太小了!"),
Ordering::Greater => println!("太大了!"),
Ordering::Equal => {
println!("🎉 恭喜你猜对了!用了 {} 次", attempts);
break;
}
}
}
}
fn main() {
// 模拟从配置文件读取
let config: Option<String> = None;
// 使用 if let 处理可选值
if let Some(value) = config {
println!("使用配置:{}", value);
} else {
println!("使用默认配置");
}
// 链式处理多个可选值
let host: Option<String> = Some("localhost".to_string());
let port: Option<u16> = Some();
if let (Some(h), Some(p)) = (host, port) {
println!("服务器地址:{}:{}", h, p);
} else {
println!("配置不完整,使用默认值");
}
}
fn main() {
let n = ;
let mut a = ;
let mut b = ;
println!("斐波那契数列前 {} 项:", n);
// 使用 for 循环生成数列
for i in ..n {
if i == {
print!("{} ", a);
} else if i == {
print!("{} ", b);
} else {
let next = a + b;
print!("{} ", next);
a = b;
b = next;
}
}
println!();
}
// ❌ 不推荐:while 循环需要手动管理索引
let mut i = ;
while i < arr.len() {
println!("{}", arr[i]);
i += ;
}
// ✅ 推荐:for 循环更简洁安全
for item in arr.iter() {
println!("{}", item);
}
// ✅ 需要索引时用 enumerate()
for (index, item) in arr.iter().enumerate() {
println!("arr[{}] = {}", index, item);
}
// ❌ 冗长:只关心一种情况却写完整 match
match option {
Some(value) => println!("{}", value),
None => (),
}
// ✅ 简洁:if let 只关心匹配成功
if let Some(value) = option {
println!("{}", value);
}
// ❌ 不推荐:先声明变量再赋值
let description;
if number > {
description = "正数";
} else {
description = "非正数";
}
// ✅ 推荐:if 表达式直接返回值
let description = if number > {
"正数"
} else {
"非正数"
};
// ❌ 冗长
let mut i = ;
while i < {
// ...
i += ;
}
// ✅ 简洁
for i in .. {
// ...
}

金句时间:
下篇预告:
学会了流程控制,接下来咱们要聊聊函数!函数是代码的基本构建块,但 Rust 的函数有些"奇葩"规则:
敬请期待第 04 篇:《函数基础》!