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 提供了穷尽性的模式匹配,保证逻辑无遗漏。
有了 Struct 和 Enum,我们已经具备了构建复杂系统的基础。
下一篇,我们将暂停理论学习,用目前学到的所有知识(变量、函数、流程控制、所有权、Struct、Enum)来做一个经典实战项目:猜数字游戏。
我们将接触到文件 I/O、依赖管理 (Crates) 和随机数生成。
练习题:
- 定义一个枚举
Shape,包含Circle(f64)(半径) 和Rectangle(f64, f64)(长宽)。 - 为
Shape实现一个方法area,使用match计算不同形状的面积。
思考题:
Go 语言处理错误通常使用 (value, error) 多返回值。Rust 使用 Result<T, E> 枚举(其实跟 Option 很像)。你觉得哪种方式更好?为什么?
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
