1、例子
ifletPerson{car: Some(_),age: person_age@13..=19,name: refperson_name,..}=person{println!("{} has a car and is {} years old.",person_name,person_age);}
以上例子出现了1种隐式匹配:判断person是不是一个Person结构体,如果不是就全部不满足了
4种显式匹配:判断person的car字段是不是非None的值(即Some(_)),但不关心具体的值
判断person的age字段是不是在[13, 19]范围内(前后闭区间),并且将值绑定给person_age变量
将person的name字段的引用绑定给变量person_name
忽视person的所有其他字段,即剩余字段可以有任何值
2、定义及出没场所
模式是 Rust 中特殊的语法,它用来匹配类型中的结构,无论类型是简单还是复杂。模式不仅用于将值与结构匹配,也可将内部的值绑定给变量。模式还用于变量定义(Rust的变量定义其实只是模式的一种应用),函数和方法的参数定义,闭包的参数定义。模式常见于如下场景:let 语句
函数与闭包参数
match 表达式
if let 表达式
while let 表达式
for 表达式
3、匹配会失效吗?
模式匹配有如下两种:
refutable:可反驳的,简而言之就是匹配可能失败
irrefutable:不可反驳的,简而言之就是匹配一定成功
let(x,y)=(1,2);// "(x, y)" is an irrefutable patterniflet(a,3)=(1,2){// "(a, 3)" is refutable, and will not matchpanic!("Shouldn't reach here");}elseiflet(a,4)=(3,4){// "(a, 4)" is refutable, and will matchprintln!("Matched ({}, 4)",a);}
4、解构(destructuring)
模式可以用来解构 structs,enums,tuples。解构将值拆成一个个它的组成部分。这个解构语法与创建值的语法基本是一样的。如果模式的检查表达式里有structs,enums,tuples,那么单下划线 (_) 表示单个字段的泛匹配,(..)表示剩余所有字段的泛匹配,在解构一个数据体的是,不允许使用方式:fieldname 来表达 fieldname: fieldname(这个方式在创建变量的时候是有效的)
matchmessage{Message::Quit=>println!("Quit"),Message::WriteString(write)=>println!("{}",&write),Message::Move{x,y: 0}=>println!("move {} horizontally",x),Message::Move{..}=>println!("other move"),Message::ChangeColor{0: red,1: green,2: _}=>{println!("color change, red: {}, green: {}",red,green);}};
5、模式语法
Pattern:LiteralPattern| IdentifierPattern| WildcardPattern| RangePattern| ReferencePattern| StructPattern| TupleStructPattern| TuplePattern| GroupedPattern| SlicePattern| PathPattern| MacroInvocation
6、patterns详解
6.1、Literal patterns
LiteralPattern:BOOLEAN_LITERAL| CHAR_LITERAL| BYTE_LITERAL| STRING_LITERAL| RAW_STRING_LITERAL| BYTE_STRING_LITERAL| RAW_BYTE_STRING_LITERAL| -? INTEGER_LITERAL| -? FLOAT_LITERAL
Literal模式实现精确匹配
foriin-2..5{matchi{-1=>println!("It's minus one"),1=>println!("It's a one"),2|4=>println!("It's either a two or a four"),_=>println!("Matched none of the arms"),}}
6.2、Identifier patterns
IdentifierPattern:ref? mut? IDENTIFIER (@ Pattern ) ?
Identifier模式,将匹配到的值绑定给某个变量,这个identifier在这个模式中应该是唯一的。这个变量会shadow在这个作用于中出现的同名变量。这个新绑定的变量的作用于范围与模式所处的上下文有关(比如let绑定 或 match arm的作用域范围就不一样)
letmutvariable=10;fn sum(x: i32,y: i32)-> i32 {x+y}
let出现变量shadow时
letx=2;letx=3;
match出现变量shadow时,例如
struct Person{age: i32,}fn main(){letage=35;letperson=Person{age: 25,};matchperson.age{age@1..=30=>{println!("{:?}",age);},//other_age_name @ 1..=30 => {// println!("{:?}", age);//},_=>{}}println!("{:?}",age);}
上面的例子中age @ 1..=30出现了这种很特别的语句,这个是子模式语法 variable @ subpattern
特别的1:在identifier模式中,绑定一个变量可能会发生值的copy或者move,取决于这个值的类型是否实现了Copy
#[derive(Debug)]struct Person{name: String,}fn main(){letperson=Person{name: String::from("hello"),};matchperson{Person{name: name,}=>{println!("{:?}",name);},}println!("{:?}",person);}
上述语句会编译失败,并给出错误
error[E0382]: borrow of moved value: `person`
--> src\main.rs:35:22
|
30 | name: name @ _
| -------- value moved here
...
35 | println!("{:?}", person);
| ^^^^^^ value borrowed here after partial move
|
= note: move occurs because `person.name` has type `std::string::String`, which does not implement the `Copy` trait
上述问题,可以通过ref 或 ref mut关键字来解决,将绑定变为引用或可变引用,此处不能用 &操作符
#[derive(Debug)]struct Person{name: String,}fn main(){letmutperson=Person{name: String::from("hello"),};matchperson{Person{name: refmutname,}=>{name.push_str(",world");println!("{:?}",name);},}println!("{:?}",person);}
特别的2:Binding modes,如果一个值的引用被绑定一个非引用模式,会自动转为ref或ref mut模式
letx: &Option=&Some(3);ifletSome(y)=x{// y was converted to `ref y` and its type is &i32}
非引用模式包含除了:wildcard patterns (_),const patterns of reference types,reference patterns之外的所有模式
6.3、Wildcard pattern
WildcardPattern:_
这个模式上面已经出现过了,直接给官方reference中的例子
let(a,_)=(10,x);// the x is always matched by _// ignore a function/closure paramletreal_part=|a: f64,_: f64|{a};// ignore a field from a structletRGBA{r: red,g: green,b: blue,a: _}=color;// accept any Some, with any valueifletSome(_)=x{}
6.4、Range patterns
RangePattern:RangePatternBound ..= RangePatternBound| RangePatternBound ... RangePatternBoundRangePatternBound:CHAR_LITERAL| BYTE_LITERAL| -? INTEGER_LITERAL| -? FLOAT_LITERAL| PathInExpression| QualifiedPathInExpression
Range模式允许你匹配一个闭区间范围内的值,比如pattern 'm'..='p' 会匹配 'm', 'n', 'o', and 'p',当前允许为literals或paths,在这个 a..=b模式下必须有a<=b。a...b语法是为了保持向后兼容而留下的。这个模式当前只是用于如下scalar types。(请注意,这里与for语句中出现的range表达式不一致,for语句中使用a..b代表[a, b),这里是a...b代表[a, b) )Integer types (u8, i8, u16, i16, usize, isize, etc.).
Character types (char).
Floating point types (f32 and f64). (这个将在未来被废弃)
letvalid_variable=matchc{'a'..='z'=>true,'A'..='Z'=>true,'α'..='ω'=>true,_=>false,};println!("{}",matchph{0..=6=>"acid",7=>"neutral",8..=14=>"base",_=>unreachable!(),});// using paths to constants:println!("{}",matchaltitude{TROPOSPHERE_MIN..=TROPOSPHERE_MAX=>"troposphere",STRATOSPHERE_MIN..=STRATOSPHERE_MAX=>"stratosphere",MESOSPHERE_MIN..=MESOSPHERE_MAX=>"mesosphere",_=>"outer space, maybe",});ifletsize@binary::MEGA..=binary::GIGA=n_items*bytes_per_item{println!("It fits and occupies {} bytes",size);}// using qualified paths:println!("{}",match0xfacade{0..=::MAX=>"fits in a u8",0..=::MAX=>"fits in a u16",0..=::MAX=>"fits in a u32",_=>"too big",});
6.5、Reference patterns
ReferencePattern:(&|&&) mut? Pattern
Reference patterns 先解引用匹配的值,然后借用(borrow)它们。
letint_reference=&3;leta=match*int_reference{0=>"zero",_=>"some"};letb=matchint_reference{&0=>"zero",_=>"some"};assert_eq!(a,b);
Reference模式总是irrufutable的。
6.6、Struct patterns
StructPattern:PathInExpression {StructPatternElements ?}StructPatternElements:StructPatternFields (, | , StructPatternEtCetera)?| StructPatternEtCeteraStructPatternFields:StructPatternField (, StructPatternField) *StructPatternField:OuterAttribute *(TUPLE_INDEX:Pattern| IDENTIFIER:Pattern| ref? mut? IDENTIFIER)StructPatternEtCetera:OuterAttribute *..
Struct模式匹配所有满足子模式(subpatterns)的struct值,也被用来解构struct,可以使用 ..来忽略剩余字段,如果未指定..,则需要匹配所有字段。如果子模式(subpatterns)是refutable的,则Struct模式是refutable的。
matchs{Point{x: 10,y: 20}=>(),Point{y: 10,x: 20}=>(),// order doesn't matterPoint{x: 10,..}=>(),Point{..}=>(),}matcht{PointTuple{0: 10,1: 20}=>(),PointTuple{1: 10,0: 20}=>(),// order doesn't matterPointTuple{0: 10,..}=>(),PointTuple{..}=>(),}
6.7、Tuple struct patterns
TupleStructPattern:PathInExpression ( TupleStructItems )TupleStructItems:Pattern ( , Pattern )* ,?| (Pattern ,)* .. ( (, Pattern)+ ,? )?
Tuple struct模式匹配所有满足子模式(subpatterns)的tuple值,也被用来解构tuple,该模式是refutable的
let((feet,inches),Point{x,y})=((3,10),Point{x: 3,y: -10});
6.8、Tuple patterns
TuplePattern:( TuplePatternItems? )TuplePatternItems:Pattern ,| Pattern (, Pattern)+ ,?| (Pattern ,)* .. ( (, Pattern)+ ,? )?
Tuple模式匹配所有满足子模式(subpatterns)的tuple值,也被用来解构tuple,该模式是refutable的
leta=(1,2,String::from("hello"));iflet(x,y@2...5,z)=a{println!("{:?}, {:?}, {:?}",x,y,z);}
6.9、Grouped patterns
GroupedPattern:( Pattern )let int_reference = &3;match int_reference {&(0..=5)=> (),_ => (),}
6.10、Slice patterns
SlicePattern:[Pattern (, Pattern)* ,? ]
例子
// Fixed sizeletarr=[1,2,3];matcharr{[1,_,_]=>"starts with one",[a,b,c]=>"starts with something else",};// Dynamic sizeletv=vec![1,2,3];matchv[..]{[a,b]=>{/* this arm will not apply because the length doesn't match */}[a,b,c]=>{/* this arm will apply */}_=>{/* this wildcard is required, since the length is not known statically */}};
6.11、Path patterns(待完善)
7、参考资料