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!(), } }
每个 |
分隔的模式中的每个绑定都必须出现在分支的所有模式中。每个同名绑定必须具有相同的类型,并且具有相同的绑定模式。
匹配守卫
匹配分支可以接受匹配守卫,以进一步细化匹配案例的条件。模式守卫出现在模式之后,由 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 时,值才会从被匹配值移动或复制到变量中。这允许在守卫内部使用共享借用,而不会在守卫匹配失败的情况下从被匹配值中移出。此外,通过在评估守卫时持有共享引用,还可以防止守卫内部发生突变。