第 4 章:还在写 `for (int i = 0; i < 10; i++)`?

住手!你这样写了多少年烂代码了?

别以为控制流就是把 iffor 从 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

你以为你懂面向对象?等着被教育吧。