跳转至

模式与匹配:参考级全景

这一章讲什么: 第 6 章用了 match,本章把"模式"这个主题讲全—— 模式不只是 match 的配件:let 的左边、函数参数、for 循环的变量,全是模式。 读完你会得到:一张"什么位置允许什么模式"的判定表,和全部模式语法的速查。 这一章定位是参考章:不必通记,知道每个武器存在、回得来查即可。

1. 顶层全景:模式出现在哪

  let PATTERN = 表达式          → 只许"不可失败"的模式
  fn f(PATTERN: T) / 闭包参数    → 只许不可失败
  for PATTERN in ...           → 只许不可失败
  match / if let / while let / let...else → 可失败
     (match 要求穷尽;if let 系不检查穷尽)

  图说:左边一列是"匹配失败就没法继续"的地方,所以只许总能成功的模式;
  右边一列是"为失败准备了出路(别的臂/else)"的地方,允许可失败模式。

let x = 5 的 x 就是模式(把匹配到的一切绑给 x);let (x, y, z) = (1, 2, 3) 是元组解构——元素个数对不上直接 E03081。if let 链可以混 else if 普通条件和 else if let 不同模式——比 match 灵活,但失去穷尽性检查(漏了 else 编译器不吱声)2。while let 循环:"模式还匹配就继续"(第 17 章的 while let Some(v) = rx.recv().await 就是用它)3。for 循环的 (index, value) 模式配 enumerate,是最常用的解构之一4。

2. Refutability:模式可能失败吗

不可失败(irrefutable)模式:对任何值都能匹配(x、_、(x, y))。可失败(refutable)模式:对某些值会失配(Some(x) 遇 None 即失败)。

规则一句话:匹配失败时程序"无处可去"的位置,只许不可失败模式。把 let Some(x) = opt; 写进 let 会吃 E0005(refutable pattern in local binding)——因为 None 来了没法办。出路是 let Some(x) = opt else { return };(let...else 接受可失败模式,else 必须发散);反过来,给 let...else 一个永远匹配的模式,编译器警告"else 是死代码"5。

3. 模式语法速查

匹配字面量:1 => ...。 多个模式:1 | 2 => ...(或运算符)。 范围:1..=5 => ...、'a'..='j' => ...——闭区间,只允许数字和 char(编译期要能判空)6。

解构:结构体 Point { x, y }(字段名简写);枚举 Some(i)、Message::Move { x, y };混合:Point { x, y: 0 } 只对 y 做字面量测试、x 照样绑变量7。元组、嵌套引用皆可解构。

忽略值的四种姿势(本章的一半篇幅):

写法 干什么 绑不绑定
_ 匹配任意值、整条臂忽略 不绑定(值不被 move)
_ 嵌在模式里 只忽略一部分,如 Some(_) 不绑定
_x(下划线开头名字) 占位但绑定值(会 move!) 绑定
.. 忽略剩余所有部分,如 Point { x, .. } 不绑定

区别有实战后果:if let Some(_s) = s 会把 String move 进 _s,后面再用 s 报错;Some(_) 则不碰所有权。.. 每个元组模式只能出现一次——(.., second, ..) 有二义性,编译错8。

Match guard(匹配守卫):Some(n) if n == y => ...——模式后面跟 if 附加条件。两个要点: ① guard 里用的是外层变量(不引入新绑定),这正是"模式变量遮蔽外层同名变量"问题的解法——Some(y) 会遮蔽外面的 y,Some(n) if n == y 不会9。 ② 有 guard 时编译器不做穷尽性检查(条件无法静态枚举)。guard 对 | 组合的模式整体生效:4 | 5 | 6 if y 等价于 (4 | 5 | 6) if y,不是 4 | 5 | (6 if y)10。

@ 绑定:id @ 3..=7 => ...——一边测范围一边把值存进变量。不用 @,要么只测范围(值丢了),要么只绑值(没测)11。

4. 作者的判断与证据

  • "大多数情况不用操心 refutability,认识它是为了看懂报错"——本章自我定位:参考章12。
  • "模式变量遮蔽是 match/if let 的新作用域所致"——机制说明,配了 Some(y) 的经典反例9。

判断(我们的,不是书里的): 本章的一个隐藏主线是"绑定的边界=所有权的边界": 每个模式都要问一句"这个变量绑走值了吗"——_ 不绑(值留着),_x 绑(值 move 走), ref 模式借,@ 边测边绑。模式语法的复杂度,一半是所有权语义逼出来的。 带着这个问题读语法表,每一行都有理由。 如果错,会错在: "绑定即 move"只对非 Copy 类型成立;Copy 类型(_x)只是复制,不夺所有权—— 文中 String 的例子是非 Copy 场景,读的时候别外推到 i32。

5. 边界与局限

  • guard 不做穷尽性检查是明确的取舍,没有给替代方案(只能自己留意)。
  • 模式匹配的编译实现(决策树等)完全没提。
  • 结构体更新语法(..=)之类的表达式语法不在本章范围。

6. 可带走的

  1. let/函数参数/for 只许不可失败模式;match/if let/while let/let...else 允许可失败。
  2. let Some(x) = opt else { ... } 是 let 处使用可失败模式的唯一通道。
  3. | 多模式、..= 范围(仅数字/char)、字面量、解构(结构体/枚举/元组)。
  4. 忽略:_(不绑)、_x(绑、会 move)、..(忽略其余、每模式一次)。
  5. match guard:用外层变量、不做穷尽检查、对 | 整体生效。
  6. @ 绑定:测模式的同时存值。
  7. 模式里的变量遮蔽外层;要比较外层值,用 guard。

7. 原文地图

主题 原书章 原文位置
let 即模式 Chapter 19: Patterns and Matching text/26-ch19-chapter-19-patterns-and-matching.txt:74(搜「PATTERN = EXPRESSION」)
if let 链与失穷尽 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:122(搜「Conditional if let」) · text/26-ch19-chapter-19-patterns-and-matching.txt:176(搜「check for exhaustiveness」)
while let 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:180(搜「while let Conditional Loops」)
for 与函数参数模式 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:208(搜「for Loops」) · text/26-ch19-chapter-19-patterns-and-matching.txt:234(搜「Function Parameters」)
refutability 与 E0005 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:268(搜「Refutability」) · text/26-ch19-chapter-19-patterns-and-matching.txt:303(搜「refutable pattern in local binding」)
let...else 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:326(搜「let Some(x) = some_option_value else」)
字面量/多模式/范围 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:369(搜「Matching Literals」) · text/26-ch19-chapter-19-patterns-and-matching.txt:451(搜「Ranges of Values」)
解构结构体 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:484(搜「Destructuring」)
忽略值四姿势 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:677(搜「Ignoring Values」) · text/26-ch19-chapter-19-patterns-and-matching.txt:781(搜「subtle difference」) · text/26-ch19-chapter-19-patterns-and-matching.txt:814(搜「Remaining Parts」)
match guard 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:921(搜「match guard gives us」) · text/26-ch19-chapter-19-patterns-and-matching.txt:986(搜「precedence」)
@ 绑定 同上 text/26-ch19-chapter-19-patterns-and-matching.txt:992(搜「at operator」)


  1. 出处:「Chapter 19: Patterns and Matching」第 74 段(text/26-ch19-chapter-19-patterns-and-matching.txt:74,搜「PATTERN = EXPRESSION」)。 ↩

  2. 出处:「Chapter 19: Patterns and Matching」第 176 段(text/26-ch19-chapter-19-patterns-and-matching.txt:176,搜「check for exhaustiveness」)。 ↩

  3. 出处:「Chapter 19: Patterns and Matching」第 180 段(text/26-ch19-chapter-19-patterns-and-matching.txt:180,搜「while let Conditional Loops」)。 ↩

  4. 出处:「Chapter 19: Patterns and Matching」第 208 段(text/26-ch19-chapter-19-patterns-and-matching.txt:208,搜「for Loops」)。 ↩

  5. 出处:「Chapter 19: Patterns and Matching」第 303 段(text/26-ch19-chapter-19-patterns-and-matching.txt:303,搜「refutable pattern in local binding」)与第 326 段(text/26-ch19-chapter-19-patterns-and-matching.txt:326,搜「let Some(x) = some_option_value else」)。 ↩

  6. 出处:「Chapter 19: Patterns and Matching」第 451 段(text/26-ch19-chapter-19-patterns-and-matching.txt:451,搜「Ranges of Values」)。 ↩

  7. 出处:「Chapter 19: Patterns and Matching」第 484 段(text/26-ch19-chapter-19-patterns-and-matching.txt:484,搜「Destructuring」)。 ↩

  8. 出处:「Chapter 19: Patterns and Matching」第 677 段(text/26-ch19-chapter-19-patterns-and-matching.txt:677,搜「Ignoring Values」)与第 781 段(text/26-ch19-chapter-19-patterns-and-matching.txt:781,搜「subtle difference」)。 ↩

  9. 出处:「Chapter 19: Patterns and Matching」第 937 段(text/26-ch19-chapter-19-patterns-and-matching.txt:937,搜「if n == y」)。 ↩↩

  10. 出处:「Chapter 19: Patterns and Matching」第 921 段(text/26-ch19-chapter-19-patterns-and-matching.txt:921,搜「match guard gives us」)与第 986 段(text/26-ch19-chapter-19-patterns-and-matching.txt:986,搜「precedence」)。 ↩

  11. 出处:「Chapter 19: Patterns and Matching」第 992 段(text/26-ch19-chapter-19-patterns-and-matching.txt:992,搜「at operator」)。 ↩

  12. 出处:「Chapter 19: Patterns and Matching」第 283 段(text/26-ch19-chapter-19-patterns-and-matching.txt:283,搜「shouldn’t have to worry」)。 ↩