枚举(Enum)允许我们通过列举所有可能的变体来定义一个类型。与结构体类似,枚举也可以包含数据和方法,但更适合表示”多选一”的情况。
1. 定义和使用枚举
1.1 基本定义
使用 enum 关键字定义枚举:
1 2 3 4 5 6 7 8 9
| enum IpAddrKind { V4, V6, }
fn main() { let four = IpAddrKind::V4; let six = IpAddrKind::V6; }
|
1.2 枚举携带数据
枚举的每个变体可以关联不同类型和数量的数据:
1 2 3 4 5 6 7 8 9
| enum IpAddr { V4(u8, u8, u8, u8), V6(String), }
fn main() { let home = IpAddr::V4(127, 0, 0, 1); let loopback = IpAddr::V6(String::from("::1")); }
|
1.3 多种数据形式
1 2 3 4 5 6
| enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), }
|
1.4 枚举方法
可以使用 impl 为枚举定义方法:
1 2 3 4 5 6 7 8 9 10
| impl Message { fn call(&self) { } }
fn main() { let m = Message::Write(String::from("hello")); m.call(); }
|
2. Option 枚举
Rust 没有空值(null),使用 Option<T> 表示值可能存在或不存在:
1 2 3 4
| enum Option<T> { Some(T), None, }
|
使用示例:
1 2 3 4 5
| fn main() { let some_number = Some(5); let some_string = Some("文本"); let absent_number: Option<i32> = None; }
|
注意: 必须将 Option<T> 转换为 T 才能使用,这强制我们处理可能为空的情况。
3. match 控制流
3.1 基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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, } }
|
3.2 绑定值的模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #[derive(Debug)] enum UsState { Alabama, Alaska, }
enum Coin { Penny, Nickel, Dime, Quarter(UsState), }
fn value_in_cents(coin: Coin) -> u8 { match coin { Coin::Penny => 1, Coin::Nickel => 5, Coin::Dime => 10, Coin::Quarter(state) => { println!("州的 25 美分硬币: {:?}!", state); 25 } } }
|
3.3 匹配 Option
1 2 3 4 5 6 7 8 9 10 11 12
| fn plus_one(x: Option<i32>) -> Option<i32> { match x { None => None, Some(i) => Some(i + 1), } }
fn main() { let five = Some(5); let six = plus_one(five); let none = plus_one(None); }
|
3.4 穷尽性检查
重要: match 必须覆盖所有可能的情况:
1 2 3 4 5 6
| fn plus_one(x: Option<i32>) -> Option<i32> { match x { Some(i) => Some(i + 1), } }
|
3.5 通配符 _
使用 _ 匹配剩余所有情况:
1 2 3 4 5 6 7 8 9 10 11 12
| fn main() { let dice_roll = 9; match dice_roll { 3 => add_fancy_hat(), 7 => remove_fancy_hat(), _ => reroll(), } }
fn add_fancy_hat() {} fn remove_fancy_hat() {} fn reroll() {}
|
不执行任何操作时使用 ():
1 2 3 4 5
| match dice_roll { 3 => add_fancy_hat(), 7 => remove_fancy_hat(), _ => (), }
|
4. if let 简洁控制流
4.1 基本用法
当只关心一种匹配情况时,使用 if let 更简洁:
1 2 3 4 5 6 7 8 9 10 11
| let config_max = Some(3u8); match config_max { Some(max) => println!("最大值: {}", max), _ => (), }
if let Some(max) = config_max { println!("最大值: {}", max); }
|
4.2 配合 else 使用
1 2 3 4 5 6
| let mut count = 0; if let Coin::Quarter(state) = coin { println!("州的 25 美分硬币: {:?}!", state); } else { count += 1; }
|
等价于:
1 2 3 4
| match coin { Coin::Quarter(state) => println!("州的 25 美分硬币: {:?}!", state), _ => count += 1, }
|
5. 实战示例
5.1 消息处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| enum Message { Hello, Goodbye, Body(String), Wait(String, u32), }
fn print_msg(m: Message) { match m { Message::Hello => println!("Hi"), Message::Goodbye => println!("Bye"), Message::Body(msg) => println!("{}", msg), Message::Wait(time, len) => println!("等待 {} {}", len, time), } }
|
5.2 状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| enum State { Idle, Running, Stopped, }
struct Machine { state: State, }
impl Machine { fn start(&mut self) { match self.state { State::Idle => { println!("启动中"); self.state = State::Running; } _ => println!("无法启动"), } } }
|
总结
枚举与模式匹配是 Rust 中最强大的特性之一。通过合理使用,我们可以:
- 类型安全:编译时确保处理所有可能情况
- 表达力强:不同变体可以携带不同类型数据
- 消除空指针:通过
Option<T> 安全处理空值
- 代码清晰:match 让逻辑分支一目了然
掌握枚举和模式匹配,为后续学习 Result 错误处理、trait 等高级特性打下基础。
Hooray!枚举和模式匹配学习完成!!!