Rust —— 枚举和模式匹配

枚举(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), // 单个 String
ChangeColor(i32, 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
// 编译错误!缺少 None 分支
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
// 使用 match
let config_max = Some(3u8);
match config_max {
Some(max) => println!("最大值: {}", max),
_ => (),
}

// 使用 if let(更简洁)
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!枚举和模式匹配学习完成!!!