时间:2022-6-21来源:本站原创作者:佚名

阅读本文大概需要5分钟。

大家好,我是站长polarisxu。

这是Rust劝退系列的第8个教程,探讨Rust中的模式匹配。

01match表达式

关于match表达式,很多其他语言并没有,比如Go语言。不过有些语言开始支持match,比如PHP8.0就有了match表达式。

一般地可以认为match和switch类似,所以Rust中没有switch。

match用于检查某个当前的值是否匹配一组/列值中的某一个。看一个具体的例子:

fntest_match(number:i32)-staticstr{matchnumber{//匹配单个值1={println!("One!");"One!"},//匹配多个值2

3

5

7

11="Thisisaprime",//匹配一个闭区间范围13..=19="Ateen",//处理其他情况_="Aintspecial",}}

看起来是一个简单的语法结构,但大概率在其他语言没见过。简单解释下:

跟其他语言的switch类似,可以匹配多个分支;多个分支之间,使用,分隔;在match分支中,=左侧是模式,因此叫做模式匹配,比如

表示匹配多个值;..=表示匹配一个范围;右侧是在左侧匹配成功时要执行的操作;match要求穷尽,也就是要包含所有可能的值。因此提供了_,用来处理所有其他情况,类似switch的default分支;但只要穷尽了,可以没有_;如果右侧操作是多个语句,需要放在{}中;match是表达式,它的结果是匹配到的模式中,执行操作的最后一个表达式的结果。这在Rust中是很常见的,之前提到过,Rust中一切皆表达式。所以,这个例子中match表达式的值即为函数的返回值。因此,match的所有分支必须返回同一数据类型;注意match表达式最后是否有分号的区别;

日常吐槽:在match中匹配区间,如果想和forin一样,使用..来表示半闭半开区间,结果报错。看到资料说应该使用…,但却提示该语法已废弃!为啥语法结构还不保持一致呢?!

看一个接收match结果的例子:

letboolean=true;letbinary=matchboolean{false=0,true=1,};//注意这里的分号println!("{}-{}",boolean,binary);02match其他用法

上面介绍了常规的match操作。match还有很多其他的用法。

解构

当元组和match一起时,可以解构元组。

fnmain(){//试一试将不同的值赋给`pair`letpair=(0,-2);println!("Tellmeabout{:?}",pair);//match可以解构一个元组matchpair{//解构出第二个值(0,y)=println!("Firstis`0`and`y`is`{:?}`",y),(x,0)=println!("`x`is`{:?}`andlastis`0`",x),_=println!("Itdoesntmatterwhattheyare"),//`_`表示不将值绑定到变量}}

关于枚举和指针、引用和match的结合,以后遇到再讲解。

guard语句

在match分支中可以加上过滤条件。接着上面元组解构的例子:

fnmain(){letpair=(2,-2);println!("Tellmeabout{:?}",pair);matchpair{(x,y)ifx==y=println!("Thesearetwins"),//`if`条件部分是一个卫语句(x,y)ifx+y==0=println!("Antimatter,kaboom!"),(x,_)ifx%2==1=println!("Thefirstoneisodd"),_=println!("Nocorrelation..."),}}绑定

这是什么意思呢?看一个例子:(来自rustbyexample)

//`age`函数,返回一个`u32`值。fnage()-u32{15}fnmain(){println!("Tellmetypeofpersonyouare");matchage(){0=println!("ImnotbornyetIguess"),//可以直接`match`1..=12,但怎么把岁数打印出来呢?//在1..=12分支中绑定匹配值到`n`。现在年龄就可以读取了。n

1..=12=println!("Imachildofage{:?}",n),n

13..=19=println!("Imateenofage{:?}",n),//不符合上面的范围。返回结果。n=println!("Imanoldpersonofage{:?}",n),}}

match后是一个函数,我们希望在分支中,根据匹配结果,使用age函数的返回值。当然,这个例子有点多此一举,完全可以在match之前用变量存储age函数的返回值。

那换一个例子:

fnsome_number()-Optionu32{Some(41)}fnmain(){matchsome_number(){Some(n

40..=42)=println!("TheAnswer:{}!",n),Some(n)=println!("Notinteresting...{}",n),_=(),}}关于Option以后讲解

这个例子很好的讲解了绑定的作用:分支中想要使用匹配的结果,通过

符号可以将匹配的结果和某个变量绑定,然后就可以使用这个变量了。

03iflet和whilelet

这两个结构其他语言没见过,可以理解为是某些场景下替代match,让代码更简洁,因为match必须穷尽所有情况,而iflet和whilelet没有此限制。

以下代码:

letsome_u8_value=Some(3u8);matchsome_u8_value{Some(3)=println!("three"),_=(),//有点多余}

改为iflet:

letsome_u8_value=Some(3u8);ifletSome(3)=some_u8_value{println!("three");}和match一样,iflet和whilelet都是表达式;if/whilelet等号左侧是模式,右侧是要匹配的值;所以当右侧的值和左侧的模式匹配时,执行对应的语句块;所以,有时候iflet也可以单纯的当做解构使用;iflet支持普通的elseif和else;whilelet没有else;

whilelet语法和iflet类似。这里就不举例子了。

04小结

Rust中的match虽然和其他语言的switch类似,很显然,match的复杂度比switch高。当然,不管复杂与否,最关键还是要实际使用,需要不断实际练习。

通常,match和Option、枚举一起使用,因此,在讲解这两个知识点时,一般会使用到match。

往期推荐

Rust劝退系列07:连流程控制都这么另类

我是polarisxu,北大硕士毕业,曾在等知名互联网公司工作,10多年技术研发与架构经验!年接触Go语言并创建了Go语言中文网!著有《Go语言编程之旅》、开源图书《Go语言标准库》等。

坚持输出技术(包括Go、Rust等技术)、职场心得和创业感悟!欢迎
转载请注明原文网址:http://www.coolofsoul.com/phpkf/phpkf/24179.html

------分隔线----------------------------