第 6 章:枚举与模式匹配
本章目标:用枚举表达有限状态,利用模式匹配处理每种可能情况。
定义枚举
枚举表示一个值只能属于若干变体之一。不同变体可以携带不同类型和数量的数据:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}比起用整数或字符串约定状态,枚举让合法状态显式可见。可以在 impl 中为枚举定义方法。
枚举变体可像结构体一样使用命名字段,也可使用元组字段或不携带数据。它们共享一个类型,因此函数参数可以接收整个枚举,并依据变体执行不同逻辑。枚举也可以嵌套其他枚举或结构体。
Option<T> 表达缺失值
Rust 没有空指针作为任意类型的默认值。Option<T> 把“有值”和“没有值”写进类型:
let present: Option<i32> = Some(5);
let absent: Option<i32> = None;使用 Option 时必须处理 Some(value) 与 None,从类型层面提醒调用者考虑缺失情况。Option<T> 与 T 不是同一类型,需要显式匹配或转换后才能使用内部值。
常用方法包括 is_some、is_none、map、and_then 和 unwrap_or。它们适合把简单转换或默认值逻辑留在 Option 链中;必须做多个不同动作时,match 更容易阅读。避免对外部数据直接 unwrap,除非程序逻辑已证明它一定存在。
match 穷尽处理
match 根据值的形态选择分支。编译器要求覆盖所有可能变体:
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}分支可以绑定变体中的数据。_ 可匹配其余情况;other 这类变量模式会绑定尚未匹配的值。穷尽匹配能让增加新变体后遗漏处理的代码及时暴露。
分支可以用逗号组合多个模式,也可用 if 添加匹配守卫。匹配表达式本身会产生值,所以可直接赋给变量。匹配引用时,模式可以解构其内部数据;注意是否移动了非 Copy 字段,必要时借用字段。
if let 简化单分支匹配
只关心一个模式时,if let 可以减少样板代码:
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("上限为 {max}");
}如果还要处理其余情况,可以配合 else。需要覆盖所有情况或逻辑分支较多时,使用 match 更清楚。
let...else 可在模式不匹配时提前退出当前作用域,适合“成功提取后继续、失败就返回”的校验流程:
fn port_from_config(value: Option<u16>) -> u16 {
let Some(port) = value else {
return 8080;
};
port
}小结与练习
- 枚举将有限状态及其数据建模为一个类型;
Option<T>显式表达可能缺失。 match必须穷尽,if let适合只关心少数模式的场景。- 练习:定义包含
Quit、Move和Text的消息枚举,并写函数按变体生成说明文字。
再练习:为枚举增加一个携带结构体字段的变体;用 match 计算变体对应结果,再用 if let 只处理一个状态;使用 let...else 从可选配置中取出必填字段。
下一章:使用包、crate 与模块管理项目。
官方对应章节:Enums and Pattern Matching。