Rust 学习笔记 09:枚举与模式匹配

“Null References: The Billion Dollar Mistake.” – Tony Hoare

Go 语言没有枚举(只有 iota 常量),也没有代数数据类型,更没有模式匹配。所以这一章对于 Go 开发者来说,是全新的世界。

1. 它是枚举,但又不仅仅是枚举

在 C/Go 中,Enum 通常只是整数的别名。 但在 Rust 中,Enum 可以携带数据,而且每个变体携带的数据类型可以不同。

1enum Message {
2    Quit,                       // 没有数据
3    Move { x: i32, y: i32 },    // 包含匿名结构体
4    Write(String),              // 包含 String
5    ChangeColor(i32, i32, i32), // 包含元组
6}

这一个 Enum 类型,就涵盖了消息系统的所有可能性。这比 Go 中定义一堆 struct 加上 interface 要简洁直观得多。

2. Option 枚举:告别 Null

Rust 没有 null。 那我想要表达"变量可能为空"怎么办? Rust 标准库提供了一个枚举 Option<T>

1enum Option<T> {
2    Some(T),
3    None,
4}

这强迫你在使用变量之前,必须处理 None 的情况。 你不能直接把 Option<i32> 当成 i32 来加减乘除,编译器会按头让你检查。这就从根源上消灭了 NullPointerException

3. match 模式匹配

有了强大的 Enum,必须要有强大的控制流来处理它。这就是 match

1let msg = Message::Write(String::from("hello"));
2
3match msg {
4    Message::Quit => println!("Quit"),
5    Message::Write(text) => println!("Text: {}", text),
6    // 必须覆盖所有情况,否则编译报错 (Exhaustiveness checking)
7    _ => (), // 处理其他情况
8}

match 就像是 Go 的 switch 的超级进化版。它不仅能匹配值,还能解构(Destructure)把数据取出来(比如上面的 text)。

4. if let 语法糖

如果你只关心一种情况,写 match 太啰嗦:

1let config_max = Some(3u8);
2
3// 只想处理 Some 的情况
4if let Some(max) = config_max {
5    println!("The maximum is configured to be {}", max);
6}

这读作:“如果 config_max 能解构出 Some(max),那就…"。这一点都不像 if,更像是一种模式匹配的简写。

5. 小结

第九篇笔记,我们解锁了 Rust 类型系统的另一半版图。

  • Enum 是代数数据类型,可以携带数据。
  • Option 替代了 Null,强制空值检查。
  • Match 提供了穷尽性的模式匹配,保证逻辑无遗漏。

有了 StructEnum,我们已经具备了构建复杂系统的基础。 下一篇,我们将暂停理论学习,用目前学到的所有知识(变量、函数、流程控制、所有权、Struct、Enum)来做一个经典实战项目:猜数字游戏

我们将接触到文件 I/O、依赖管理 (Crates) 和随机数生成。


练习题

  1. 定义一个枚举 Shape,包含 Circle(f64) (半径) 和 Rectangle(f64, f64) (长宽)。
  2. Shape 实现一个方法 area,使用 match 计算不同形状的面积。

思考题

Go 语言处理错误通常使用 (value, error) 多返回值。Rust 使用 Result<T, E> 枚举(其实跟 Option 很像)。你觉得哪种方式更好?为什么?


本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读