match 表达式

语法
匹配表达式 :
   match 待匹配表达式 {
      内部属性*
      匹配分支?
   }

待匹配表达式 :
   表达式不包括结构体表达式

匹配分支 :
   ( 匹配分支项 => ( 无块表达式 , | 有块表达式 ,? ) )*
   匹配分支项 => 表达式 ,?

匹配分支项 :
   外部属性* 模式 匹配分支守卫?

匹配分支守卫 :
   if 表达式

一个 match 表达式 根据模式进行分支。实际发生的匹配形式取决于 模式

一个 match 表达式有一个 待匹配表达式,它是用于与模式比较的值。

待匹配表达式和模式必须具有相同的类型。

match 的行为方式取决于待匹配表达式是 位置表达式还是值表达式

如果待匹配表达式是 值表达式,它会首先被求值到一个临时位置,然后将结果值依次与分支中的模式进行比较,直到找到匹配项。第一个匹配到模式的分支项被选作 match 的分支目标,模式绑定的任何变量都会被赋值给分支项块中的局部变量,然后控制流进入该块。

当待匹配表达式是 位置表达式 时,match 不会分配临时位置;然而,按值绑定可能会从内存位置进行复制或移动。如果可能,最好对位置表达式进行匹配,因为这些匹配的生命周期继承自位置表达式的生命周期,而不是仅限于 match 内部。

match 表达式的一个示例

#![allow(unused)]
fn main() {
let x = 1;

match x {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    4 => println!("four"),
    5 => println!("five"),
    _ => println!("something else"),
}
}

在模式中绑定的变量的作用域为匹配守卫和分支项的表达式。

绑定模式(移动、复制或引用)取决于模式。

可以使用 | 运算符连接多个匹配模式。每个模式将从左到右依次进行测试,直到找到成功的匹配项。

#![allow(unused)]
fn main() {
let x = 9;
let message = match x {
    0 | 1  => "not many",
    2 ..= 9 => "a few",
    _      => "lots"
};

assert_eq!(message, "a few");

// Demonstration of pattern match order.
struct S(i32, i32);

match S(1, 2) {
    S(z @ 1, _) | S(_, z @ 2) => assert_eq!(z, 1),
    _ => panic!(),
}
}

注意

2..=9 是一个 范围模式,而不是 范围表达式。因此,在匹配分支中只能使用范围模式支持的范围类型。

每个通过 | 分隔的模式中的每个绑定都必须出现在该分支项的所有模式中。

相同名称的每个绑定必须具有相同的类型和相同的绑定模式。

匹配守卫

匹配分支项可以接受 匹配守卫,以进一步细化匹配某个情况的条件。

模式守卫出现在模式之后,由一个 if 关键字后跟一个 bool 类型的表达式组成。

当模式成功匹配时,模式守卫表达式会执行。如果表达式求值为 true,则该模式被视为成功匹配。

否则,将测试下一个模式,包括同一分支项中使用 | 运算符的其他匹配项。

#![allow(unused)]
fn main() {
let maybe_digit = Some(0);
fn process_digit(i: i32) { }
fn process_other(i: i32) { }
let message = match maybe_digit {
    Some(x) if x < 10 => process_digit(x),
    Some(x) => process_other(x),
    None => panic!(),
};
}

注意

使用 | 运算符的多个匹配可能会导致模式守卫及其附带效应多次执行。例如

#![allow(unused)]
fn main() {
use std::cell::Cell;
let i : Cell<i32> = Cell::new(0);
match 1 {
    1 | _ if { i.set(i.get() + 1); false } => {}
    _ => {}
}
assert_eq!(i.get(), 2);
}

模式守卫可以引用其后模式中绑定的变量。

在求值守卫之前,会获取待匹配表达式中该变量匹配部分的共享引用。在求值守卫期间,访问该变量时会使用这个共享引用。

只有当守卫求值为 true 时,值才会从待匹配表达式中移动或复制到变量中。这使得共享借用可以在守卫中使用,而不会在守卫匹配失败时移动出待匹配表达式。

此外,在求值守卫时持有共享引用,也防止了在守卫内部进行修改。

匹配分支项上的属性

外部属性允许用于匹配分支项。唯一对匹配分支项有意义的属性是 cfglint 检查属性

内部属性 允许直接在 match 表达式的左大括号之后使用,其表达式上下文与 块表达式上的属性 相同。