match 表达式

语法

MatchExpression :

   match 被匹配值 {

      内部属性*

      匹配分支?

   }

被匹配值 :

   表达式结构体表达式除外

匹配分支 :

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

   匹配分支项 => 表达式 ,?

匹配分支项 :

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

匹配分支守卫 :

   if 表达式

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 检查属性

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