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!(), } }
每个通过 | 分隔的模式中的每个绑定都必须出现在该分支项的所有模式中。
相同名称的每个绑定必须具有相同的类型和相同的绑定模式。
匹配守卫
匹配分支项可以接受 匹配守卫,以进一步细化匹配某个情况的条件。
模式守卫出现在模式之后,由一个 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 时,值才会从待匹配表达式中移动或复制到变量中。这使得共享借用可以在守卫中使用,而不会在守卫匹配失败时移动出待匹配表达式。
此外,在求值守卫时持有共享引用,也防止了在守卫内部进行修改。