18.1 能用到模式(匹配)的地方
18.1.1. 什么是模式
模式(pattern)是 Rust 里一种特殊的语法,用于匹配复杂类型和简单类型的结构。
将模式与match表达式以及其他构造结合使用,可以更好地控制程序的流程。
模式由以下元素的一些组合构成:
- 字面值
- 解构的数组、enum、struct和元组
- 变量
- 通配符
- 占位符
想要使用模式,需要将它与某个值进行比较:如果模式匹配,就可以在代码中使用这个值的相应部分。
18.1.2.match的分支(Arm)
arm(分支)可以使用模式。它的形式是:
match VALUE { PATTERN => EXPRESSION, PATTERN => EXPRESSION, PATTERN => EXPRESSION, }match必须是穷尽的,也就是说你必须覆盖所有可能的情况。
match中也经常用到_通配符。它会匹配任何东西,并且不会绑定到变量上。它通常用于match的最后一个分支,或用于忽略某个值。
如果想看更详细的介绍,可以去 6.3. 控制流运算符-match。
18.1.3.if let表达式
if let表达式可以看作是只匹配一种可能性的match表达式。
它还可以可选地包含:
-else if
-else
-else if let
与match相比,if let的缺点是不会检查穷尽性。如果我们省略了最后的else块,从而漏掉对某些情况的处理,编译器不会提醒我们可能存在逻辑错误。看个例子:
fn main() { let favorite_color: Option<&str> = None; let is_tuesday = false; let age: Result<u8, _> = "34".parse(); if let Some(color) = favorite_color { println!("Using your favorite color, {color}, as the background"); } else if is_tuesday { println!("Tuesday is green day!"); } else if let Ok(age) = age { if age > 30 { println!("Using purple as the background color"); } else { println!("Using orange as the background color"); } } else { println!("Using blue as the background color"); } }如果用户指定了最喜欢的颜色,就用该颜色作为背景。如果没有指定最喜欢的颜色,并且今天是星期二,则背景颜色为绿色。否则,如果用户把年龄指定为字符串,并且我们能成功把它解析为数字,则颜色为紫色或橙色,具体取决于这个数值。如果这些条件都不适用,则背景颜色为蓝色。
这种条件结构让我们能够支持复杂的需求。使用这里写死的值时,这个例子会打印Using purple as the background color。
你可以看到,if let也可以像match一样引入遮蔽变量:if let Ok(age) = age这一行引入了一个新的遮蔽变量age,其中包含Ok里的值。这意味着,在使用上面这种嵌套写法时,我们需要把if age > 30放在那个块里:我们想与30比较的那个遮蔽后的age,只在以{大括号开始的新作用域内有效。从 Rust 2024 edition 开始,let chains(let链)也允许把模式匹配和布尔条件写在同一个条件里,例如if let Ok(age) = age && age > 30;此时Ok(age)绑定出的变量可以在同一条&&链的后续部分中使用。
其余详细内容可见 6.4. 简单的控制流-if let。
18.1.4.while let条件循环
while let和if let有点相似:只要模式继续匹配,它就允许while循环一直运行。
看个例子:
let mut stack = Vec::new(); stack.push(1); stack.push(2); stack.push(3); while let Some(top) = stack.pop() { println!("{top}"); }这个例子会依次打印 3、2、1。pop方法会从向量中取出最后一个元素并返回Some(value)。如果向量为空,pop返回None。只要pop返回Some,while循环就会继续运行其块中的代码。当pop返回None时,循环停止。我们可以用while let把栈中的每个元素依次弹出。
18.1.5.for循环
for循环是 Rust 中最常见的循环。在for循环中,模式就是紧跟在for关键字后面的那个值。
在for循环中,直接跟在关键字for后面的值是一个模式。例如,在for x in y中,x就是模式。下面的例子演示了如何在for循环中使用模式来解构元组:
let v = vec!['a', 'b', 'c']; for (index, value) in v.iter().enumerate() { println!("{value} is at index {index}"); }输出:
a is at index 0 b is at index 1 c is at index 2其余信息可见 3.6. 控制流:循环。
18.1.6.let语句
let语句也是模式,其语法是:
let PATTERN = EXPRESSION;看个例子:
let (x, y, z) = (1, 2, 3);我们将元组与模式进行匹配。Rust 会把值(1, 2, 3)与模式(x, y, z)比较,并发现该值与模式匹配,于是把1绑定到x,把2绑定到y,把3绑定到z。你可以把这个元组模式看成其中嵌套了三个单独的变量模式。
18.1.7. 函数参数
函数参数也可以是模式。看个例子:
fn foo(x: i32) { // ... }其中的x部分就是一个模式。
正如我们对let所做的那样,我们也可以在函数参数中把元组与模式进行匹配。例如:
fn print_coordinates(&(x, y): &(i32, i32)) { println!("Current location: ({x}, {y})"); } fn main() { let point = (3, 5); print_coordinates(&point); }