前言#
昨天我们学了enum以及Option
今天我们继续往下学
match控制流结构#
其实我们之前就用过了,在第二天写一个猜数游戏。
在比对数值的时候就用了这个match模式匹配,匹配比较的变体(variant),有大于、小于以及等于三种变体。
match可以用于字面量、 变量、通配符等其他各种东西匹配,是非常强大的功能。
我们来看下一个例子
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn main () {
let value = value_in_cents(Coin::Penny);
println!("{value}");
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}我们先是声明了一个枚举Coin,然后又声明了一个函数value_in_cents,参数是Coin也就是枚举类型,返回一个u8的数据。
之前有一个点我们忘了说了,枚举的变体是可以不用设置默认值的
我们跑下代码

我们先是声明了一个Coin的变体Penny 然后match了Coin这个枚举的所有变体(variant)。 接着匹配到了一个penny便士值输出为1。
模式匹配的关键字是match,然后跟匹配的目标, 然后就是{} 。
所以结构是这样:match xxx {}。
=> 1是=> { 1 }的简写,表示匹配到的语句。
而Coin::Penny => 1这一条语句被叫做arms.
每条arms或者说是表达式的返回值都将作为这个match表达式的返回值。
这种代码在js中一般用对象匹配或者if条件判断等,用if条件判断会有些冗长,而用对象匹配的话会有些拘束性。
模式绑定值(patterns that bind to values)#
这名字。。。我真的不知道翻译成啥
还记得我们昨天学的enum的变体可以绑定一个数据吗?这个绑定可以用于match中,我们来看下。
#[derive(Debug)] // so we can inspect the state in a minute
enum UsState {
Alabama,
Alaska,
// --snip--
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
} 还是我们的硬币枚举,
不同的是四分之一镑(25美分)绑定了一个UsState的枚举。
然后我们再改下方法value_in_cents
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
}
}
} 和之前不同的是Coin::Quarter后面还接上了(state)。
然后我们来调用下
fn main () {
let value = value_in_cents(Coin::Quarter(UsState::Alabama));
println!("{value}");
} 
如果匹配到了这个quarter的变体,就会把这个UsState::Alabama的枚举变体当做state这个变量传入大括号中作为参数。
匹配Option#
还记得昨天我们学的Option这个类型吗?
它也能用来匹配,而且也非常是和match,用来判断一个值是否有效
fn main () {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
dbg!(five, six, none);
}
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}我们创建了三个变量five、six、none以及plus_one方法
当我们匹配到None这个变体的时候就返回None,而Some的时候就返回Some(i + 1)。
我们来打印下

match需要全面(match are exhaustive)#
啥意思捏?其实很容易理解,按rust强调的安全性,如果你一个match只匹配了一个场景,但实际上存在多个场景,这时候就有可能引起报错,所以rust中使用match需要你穷举所有场景,这样才能保证不会出错。

但是这样是不人道的,因为你这个枚举可能有N个值,比如:我们全国各地的美食doge~。
所以官方提供了一种方式允许你不处理其他场景,专注于其中某几个场景。
往下看。
全捕获模式和_占位符(catch-all patterns and _ placeholder)#
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
other => move_player(other),
}
fn add_fancy_hat() {}
fn remove_fancy_hat() {}
fn move_player(num_spaces: u8) {}上面的代码执行了之后会走other这个arms

这样你就能专注于3和7的场景,其他场景统一处理。
另外,如果我们不想处理other场景,这样也是可以的,比如:
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
// other => move_player(other),
_ => (),
} _这个符号是获取不到值的,所以它并不能用于参数,它仅仅表示一个占位符,用在你完全不想处理其余场景时。
但是如果你没有列举所有场景时不写是不行的哦。《安全》
如果我们只想处理一种场景,其他场景都不想处理,这个时候rust还提供了一种方式来简写
使用if let简洁化控制流(concise control flow with if let)#
如标题所说,上面提到的只需要处理一种情况的场景可以用if let来简洁match的用法。
比如原来我们需要用这样写
let config_max = Some(3u8);
match config_max {
Some(max) => println!("The maximum is configured to be {}", max),
_ => (),
} 虽然挺简洁了,但是我们还想更简洁,就像js函数声明改成箭头函数一样(不是很恰当,因为函数声明和箭头函数两者不同点挺多)
我们可以用if let改成下面这个样子
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("The maximum is configured to be {}", max);
} 只处理Some(max) = config_max的场景,而不处理None的场景。
但如果我们还想处理None的场景呢?(事真多)
其实也是可以滴,既然有if那自然有else,比如:
let mut count = 0;
match coin {
Coin::Quarter(state) => println!("State quarter from {:?}!", state),
_ => count += 1,
}可以调整为
let mut count = 0;
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
count += 1;
}不过用不用取决于你自己~
总结#
今天我们学了match模式匹配,以及全捕获匹配和if let等。
明天居家,隔壁老哥阳了~
如果觉得对你用帮助,麻烦点个赞,谢谢~
参考#
- ^rust-match-control-flow-construct https://doc.rust-lang.org/book/ch06-02-match.html#the-match-control-flow-construct
- ^rust-patterns-that-bind-to-values https://doc.rust-lang.org/book/ch06-02-match.html#patterns-that-bind-to-values
- ^rust-match-option https://doc.rust-lang.org/book/ch06-02-match.html#matching-with-optiont
- ^rust-match-are-exhaustive https://doc.rust-lang.org/book/ch06-02-match.html#matches-are-exhaustive
- ^rust-catch_all_patterns_and__placeholder https://doc.rust-lang.org/book/ch06-02-match.html#catch-all-patterns-and-the-_-placeholder
- ^rust-concise-control-flow-with-if-let https://doc.rust-lang.org/book/ch06-03-if-let.html#concise-control-flow-with-if-let
编辑于 2022-12-09 11:20・IP 属地广东
