match
表达式
语法
MatchExpression :
match
Scrutinee{
InnerAttribute*
MatchArms?
}
Scrutinee :
Expressionexcept struct expressionMatchArms :
( MatchArm=>
( ExpressionWithoutBlock,
| ExpressionWithBlock,
? ) )*
MatchArm=>
Expression,
?MatchArm :
OuterAttribute* Pattern MatchArmGuard?MatchArmGuard :
if
Expression
match
表达式 基于模式进行分支。发生的匹配的具体形式取决于模式。match
表达式有一个scrutinee 表达式,它是要与模式比较的值。scrutinee 表达式和模式必须具有相同的类型。
match
的行为取决于 scrutinee 表达式是位置表达式 还是 值表达式。如果 scrutinee 表达式是值表达式,它首先被求值到一个临时位置,然后将结果值按顺序与 arm 中的模式进行比较,直到找到匹配项。具有匹配模式的第一个 arm 被选为 match
的分支目标,模式绑定的任何变量都分配给 arm 代码块中的局部变量,并且控制权进入该代码块。
当 scrutinee 表达式是位置表达式 时,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"), } }
在模式中绑定的变量的作用域限定于 match guard 和 arm 的表达式。绑定模式(移动、复制或引用)取决于模式。
多个 match 模式可以使用 |
运算符连接。每个模式将按从左到右的顺序进行测试,直到找到成功的匹配项。
#![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
是一个 范围模式,而不是一个 范围表达式。因此,只有范围模式支持的那些类型的范围才能在 match arm 中使用。
每个 |
分隔的模式中的每个绑定都必须出现在 arm 中的所有模式中。每个同名的绑定都必须具有相同的类型,并且具有相同的绑定模式。
Match guards
Match arm 可以接受 match guards 以进一步细化匹配 case 的标准。模式 guard 出现在模式之后,由一个 bool
类型的表达式组成,后跟 if
关键字。
当模式成功匹配时,将执行模式 guard 表达式。如果表达式求值为 true,则模式成功匹配。否则,将测试下一个模式,包括同一 arm 中使用 |
运算符的其他匹配项。
#![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!(), }; }
注意:使用
|
运算符的多个匹配可能会导致模式 guard 及其产生的副作用多次执行。例如#![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); }
模式 guard 可以引用在其跟随的模式中绑定的变量。在评估 guard 之前,会获取对 scrutinee 中变量匹配部分的共享引用。在评估 guard 时,然后在访问变量时使用此共享引用。仅当 guard 评估为 true 时,值才会从 scrutinee 移动或复制到变量中。这允许在 guard 内部使用共享借用,而不会在 guard 未能匹配的情况下移出 scrutinee。此外,通过在评估 guard 时保持共享引用,还可以防止 guard 内部的突变。
Match arm 上的属性
Match arm 允许外部属性。在 match arm 上有意义的唯一属性是 cfg
和 lint check 属性。