住手!你这样写了多少年烂代码了?
别以为控制流就是把 if
、for
从 Java 搬到 Rust。那点语法糖解决不了你的根本问题:你的思维还停留在上世纪。
Rust 的控制流要重新定义你对"控制"这个概念的理解。准备好接受降维打击了吗?
核心革命:从语句到表达式
第一课:忘掉你学过的一切。
在 Java 里,if
是个语句。语句就是"执行一个动作,然后什么都不返回"。想用 if
做赋值?要么用那个丑陋的三元运算符 condition ? a : b
,要么写一堆冗余代码。
// Java 的痛苦
int number;
if (condition) {
number = 5;
} else {
number = 6;
}
Rust 说:这是什么垃圾代码?
if-else:不只是判断,更是武器
看看什么叫优雅:
let number = if condition { 5 } else { 6 };
一行搞定!这就是表达式的威力。
还觉得没什么?再看这个:
let status_message = if user.is_premium() {
"尊贵的VIP用户"
} else if user.is_member() {
"普通会员"
} else {
"访客"
};
在 Java 里写这种逻辑,你要么用一堆 if-else
然后反复赋值,要么用那个恶心的三元运算符嵌套。都 2025 年了,还在折磨自己?
类型安全:编译器不允许你犯蠢
试试这个,看编译器怎么教你做人:
// 编译错误!滚去重写!
let number = if condition { 5 } else { "six" };
编译器直接拒绝编译。在 Java 里这种混合类型的赋值能通过编译,然后在运行时给你一个 ClassCastException
当惊喜。
Rust 表示:我不给你犯错误的机会。
循环:重复的艺术
loop:无限循环也能返回值
Java 的 while(true)
循环能返回值吗?当然不能,因为它是语句。
Rust 的 loop
:让你见识什么叫真正的控制流。
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // 跳出循环并返回值
}
};
// result 现在是 20
这种"重试直到成功并返回结果"的模式,在 Java 里要写一堆冗余代码。Rust 一个 loop
就解决了。
这不是语法糖,这是思维方式的升级。
while:老朋友,没什么好说的
while number != 0 {
println!("{}!", number);
number -= 1;
}
和 Java 一样,但是记住:Rust 的 while
也是表达式,只是返回 ()
(unit type)。
for:告别索引地狱
看看你以前写的垃圾:
// Java 的原始做法
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
数组越界了多少次?off-by-one 错误犯了多少回?
Rust 说:停止自我折磨。
// 范围遍历
for number in 1..4 { // 1, 2, 3 (不包含4)
println!("{}!", number);
}
// 数组遍历
let array = [10, 20, 30, 40, 50];
for element in array.iter() {
println!("the value is: {}", element);
}
彻底消灭索引。彻底消灭边界错误。
你只需要关心每个元素,让编译器处理那些无聊的细节。这就是Zero-cost abstraction——抽象不带来性能损失,还让代码更安全。
match:让 switch 颤抖的存在
Java 的 switch
是什么垃圾?
- 忘写
break
就出 bug - 没有
default
编译器也不管 - 只能匹配几种基础类型
Rust 的 match
:这才是 21 世纪的模式匹配。
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
穷尽性检查:编译器强制你考虑所有情况
这是 match 的杀手锏。
如果你漏掉任何一个 Coin
的变体,编译器直接拒绝编译。没有运行时惊喜,没有未处理的 case,没有默默失败的逻辑。
在 Java 里忘记写 default
?运行时才知道出错。在 Rust 里?编译都过不了。
模式匹配:提取数据的黑魔法
这才是真正的威力:
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1), // 提取出 i,加1后重新包装
}
}
看到了吗?match
不只是比较值,它能深入数据结构内部,提取你想要的部分。
Java 的 switch
能做到这个吗?做梦去吧。
多重模式和范围:一招制敌
match value {
1 | 2 => println!("一或二"),
3..=5 => println!("三到五"),
_ => println!("其他"),
}
一个 match
搞定复杂的条件组合。在 Java 里这得写多少个 if-else
?
万物皆表达式:match 也能赋值
let description = match coin {
Coin::Penny => "1分",
Coin::Nickel => "5分",
Coin::Dime => "10分",
Coin::Quarter => "25分",
};
简洁、类型安全、穷尽性检查、还是表达式。这就是现代编程语言应有的样子。
写在最后:思维的革命
今天我们见证了控制流的进化:
从"执行命令"到"计算结果"的思维转变。
if
不再是简单的分支跳转,而是计算不同条件下的值loop
不再是单纯的重复执行,而是重试直到成功的利器for
不再是索引的地狱,而是安全遍历的抽象match
不再是简单的值比较,而是数据结构的深度解构
这不是语法糖,这是编程范式的升级。
当你习惯了"万物皆表达式"的思维,你会发现:
- 代码更简洁了
- bug 更少了
- 重构更安全了
- 性能还更好了
这就是现代编程语言的威力。
我们已经学会了如何控制程序的执行流程。但程序不只是数据和控制流,还需要组织结构。
Java 里我们有 class
。Rust 里呢?
下一章我们要看看 Rust 如何重新定义"对象"这个概念。准备好被彻底颠覆吧。
因为在 Rust 的世界里,没有类,没有继承,但有比它们更强大的东西:struct
+ impl
+ trait system。
你以为你懂面向对象?等着被教育吧。