Rust 学习笔记 24:模式匹配详情 (Pattern Matching)

“Patterns are the ultimate way to deconstruct reality.”

我们在前面的章节已经频繁使用了 matchlet。其实,模式 (Pattern) 在 Rust 中无处不在。 只要涉及到数据赋值或参数传递,几乎都有模式的身影。

1. 模式无处不在

除了 match 表达式,哪里还有模式?

if let:

1if let Some(x) = option_value { ... }

while let:

1while let Some(top) = stack.pop() { ... }

for 循环:

1for (index, value) in v.iter().enumerate() { ... }

let 语句:

1let (x, y, z) = (1, 2, 3);

函数参数:

1fn print_coordinates(&(x, y): &(i32, i32)) { ... }

2. Refutability (可反驳性)

模式分为两类:

  • 不可反驳的 (Irrefutable):匹配任何可能的值。例如 let x = 5; 中的 x
  • 可反驳的 (Refutable):可能匹配失败。例如 if let Some(x) = a_value 中的 Some(x)(因为 a_value 可能是 None)。

let 语句、函数参数、for 循环只接受不可反驳的模式。如果你试图用 let Some(x) = value;,编译器会报错,因为它不能处理 None 的情况。

3. 结构与解构 (Destructuring)

解构结构体

1struct Point { x: i32, y: i32 }
2match p {
3    Point { x, y: 0 } => println!("On the x axis at {}", x),
4    Point { x: 0, y } => println!("On the y axis at {}", y),
5    Point { x, y } => println!("On neither axis"),
6}

解构枚举: 我们在 OptionResult 中已经见得多了。

忽略值

  • _:忽略单个值。
  • ..:忽略剩余值。例如 (first, .., last)

4. 匹配守卫 (Match Guards)

有时候光靠模式匹配还不够,我们需要额外的条件判断。

1let num = Some(4);
2
3match num {
4    Some(x) if x < 5 => println!("less than five: {}", x),
5    Some(x) => println!("{}", x),
6    None => (),
7}

那个 if x < 5 就是 Match Guard。

5. @ 绑定

@ 允许我们在创建一个存放值的变量的同时,测试这个值是否匹配模式。

1match msg {
2    Message::Hello { id: id_variable @ 3..=7 } => {
3        println!("Found an id in range: {}", id_variable)
4    },
5    // ...
6}

如果不使用 @,我们要么只能测试范围(拿不到具体值),要么只能拿到值(不能在模式里直接测试范围)。@ 二者兼得。

6. 小结

第24篇笔记。

  • 模式匹配是 Rust 表达力的核心之一。
  • 解构 让我们能轻松拆解复杂数据。
  • Match Guards@绑定 为匹配提供了更细粒度的控制。

下一篇,我们将进入 高级特性 (Advanced Features)。Unsafe Rust? 高级 Trait? 高级类型? 准备好迎接黑魔法了吗?


练习题

  1. 编写一个 match 表达式,匹配一个 (i32, i32) 元组,要求:如果是 (0, 0) 打印原点;如果是 (_, 0) 打印在 X 轴;如果是 (0, _) 打印在 Y 轴;如果是 x == y 打印在对角线上(使用 Match Guard)。
  2. 尝试在 if let 中使用 @ 绑定。

思考题

Rust 的模式匹配与 switch-case 的本质区别是什么?(提示:它是基于结构和值的匹配,还是仅仅是值的跳转?)


本文代码示例

关注公众号:极客老墨

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

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

相关阅读