rust键位失灵_Rust:模式匹配(patterns)

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 pattern​iflet(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 ... RangePatternBound​RangePatternBound: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)?| StructPatternEtCetera​StructPatternFields: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、参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值