enum OptionalInt {
Value(i32),
Missing,
}
let x = OptionalInt::Value(5);
match x {
OptionalInt::Value(i) if i > 5 => println!("大于5的数"),
OptionalInt::Value(..) => println!("小于等于5的数"),
OptionalInt::Missing => println!("Missing"),
}
等价于
enum OptionalInt {
Value(i32),
Missing,
}
let x = OptionalInt::Value(5);
match x {
OptionalInt::Value(i) => {
if i > 5 {
println!(">5")
}else{
println!("<=5")
}
},
OptionalInt::Missing => println!("No such luck."),
}
你可以想象一下这样的场景该如何书写:输入三个变量,当x为Dir::Left并且z==0且last为Dir::Right的时候,返回"yes",其他返回"no"
TODO match和if的性能对比。
刚开始接触Rust,边学边记录,欢迎指正。
match初识
模式匹配(Pattern matching)在Rust中非常常见,模式可以用在match、let等多个地方,本篇主要涉及到的是match表达式。模式也有很多种,如单值、多个值、范围等,后面会逐一提到。 match可以拿其他语言中的switch来做类比和对比从而加深印象。
模式匹配在Rust中通常出现在变量绑定、match语句中。TODO 那变量绑定怎么算模式匹配 模式匹配是match?还是match中可以用模式匹配
switch和穷尽性检查
match
配合多种模式比switch强大许多,不过刚开始接触match
,可以拿switch
作为类比对象,它们都可以对一个变量的值进行分支处理。不过双方本质不同导致许多行为不同,譬如
switch
有break
可以打断匹配流程。而match
则要求同时只能进入一个分支。举个不恰当的例子,switch有点像下楼梯,只要不停下来可以一直往下走,直到最底部。match则像岔口,只能从中选择匹配到的进入。 而Rust要求match穷尽出所有的可能性(exhaustiveness checking),因此不存在匹配不到的情况。
检查穷尽性可以保证我们不会忘了处理某个值。要么match中声明了所有可能的值,要么使用
_
来表达其他所有的可能性。 当然也可以使用一个新的变量来代替在这里c只在当前分支内有效。
match也是表达式
match里的每一个分支都由
val => expression
组成,当变量匹配到对应分支的val时(这个val理解为模式更好些),右侧的表达式就会开始执行。 match同样是一个表达式,这意味着它也是有返回值的。它的返回值为对应分支的表达式的返回值。在进行类型转换时,用这种写法会很不错。
match和enum
match另一个重要的场景就是匹配枚举的可能值。
由于使用
==
对比是一个trait需额外实现,所以上述代码在用if和==来模拟时是无法成功的,必须用match关键字。模式Patterns
接下来详细看看match里的模式(TODO 事实上模式也可以用在绑定,这里主要看的是match中) 模式是一个很难形象理解的东西,它既可以用在match里,也经常出现在let绑定中。类似的解构可以类比一下。 模式有很多种,需要多写来掌握不同的模式的最佳应用场景。
多重匹配
可以使用
|
进行多重匹配解构
对于复合数据类型,例如struct,可以在模式匹配中使用解构
还可以通过
:
解构为另外一个名字这里还可以
..
忽略一些不用的值解构可以用在任何复合数据类型(compound data type)。譬如enums、tuple。
忽略绑定
可以使用
_
来忽略掉不用的变量。在JS中用_和x做变量名并没有本质不同,而在Rust中则实实在在的约定不可用,譬如下面的``被用到时会无法编译。任何模式匹配中的变量绑定都可以用
_
忽略,想要去一个大的结构体的部分字段时,这个功能非常有用。 类似的可以用..
来忽略多个变量值ref和ref mut
如果想获取一个引用,可以使用ref关键字。(TODO 关于ref将来需要单独总结一篇文章)
ref
创建了一个不可变引用,如果想用可变引用需要用ref mut
范围Ranges
可以用
...
来匹配一个范围(三个点,俩点的是解构时忽略值)Ranges统一可以用给char
绑定
可以用@配合ranges做变量绑定,通常用来获取复合数据中的部分数据
使用@绑定变量应该是有开销(TODO 待总结。)
match guards
这个怎么翻译合适… 可以在分支上继续使用if来达到某些效果,有点类似于
条件1 && 条件2
中&&
的感觉等价于
你可以想象一下这样的场景该如何书写:输入三个变量,当x为Dir::Left并且z==0且last为Dir::Right的时候,返回"yes",其他返回"no" TODO match和if的性能对比。
if let和while let
match表达式配合模式虽然很强大,但面对一些场景时它的代码就显得不够“少”,为此有了
if let
和while let
表达式。(这种两个关键字组合的表达式,刚接触的时候怪怪的) 当只需要匹配一个分支的时候,可以使用if let
精简代码while let
则是处理循环时的某种情况:小结
模式匹配的精髓在于match+patterns,两者缺一不可。它提供了强大的匹配能力,但同时面对一些特殊的场景时,它需要的书写代码可能会更多。 通常会用Rust的宏来解决这些场景,提高代码的简洁性。
TODO ref文章 TODO match和if的性能测试 TODO ..和...的文章 TODO 补充解构在实际项目中的运用。 TODO if let 模式匹配变量的位置在左和右的区别
相关资料
Patterns Match