Rust 探索(九)—— 枚举与模式匹配(下)

1. 绑定值的模式

匹配分支还可以用来绑定值,这是什么意思呢?

1
2
3
4
5
6
7
// 垃圾
enum Waste {
Recyclable, // 可回收垃圾
Other, // 其他垃圾
Kitchen(Content), // 厨余垃圾,添加细分
Hazardous // 有害垃圾
}
1
2
3
4
5
6
#[derive(Debug)]
enum Content {
Peel, // 果皮
Leftovers, // 剩饭
Bone // 骨头
}

这里我们对于厨余垃圾类型进行了进一步描述,正如我们先前所了解到的,枚举类型可以添加参数,因此这里又添加了一个Content枚举,用以将厨余垃圾细分为果皮、剩饭和骨头

上面添加#[derive(Debug)],因为稍后会将其进行输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn classify(waste: Waste) -> String {
match waste {
Waste::Recyclable => String::from("蓝色"),
Waste::Other => {
println!("仔细想想,不要乱扔!");
String::from("灰色")
},
Waste::Kitchen(content) => { // 增加对参数处理
println!("厨余垃圾内容={:?}", content);
String::from("绿色")
},
Waste::Hazardous => String::from("红色")
}
}

现在在match的分支语句当中,可以对厨余垃圾分支,即Waste::Kitchen进行参数处理,content通过=>进入代码块,我们可以添加对枚举类型携带的参数的处理逻辑,这里我只是进行了简单的实例输出

2. 匹配 Option<T>

别忘了,先前我们的目的是处理Option<T>,现在回归正题

我们先前已经学会了使用match对于枚举的变体进行匹配了,那么Option<T>的道理也是一样的

Option<T>有两个变体,分别是NoneSome(T),接下来我们对号入座

1
2
3
4
5
6
7
8
9
10
fn show_number(number: Option<f64>) -> String {
match number {
None => {
String::from("--")
}
Some(value) => {
(value * 100.0).to_string() + "%"
}
}
}

这里定义了一个接收Option<f64>作为参数的方法,主要的功能就是将接收到的数据转化为百分比的格式,如果没有数据,那么默认显示–

这里便是使用match对于Option<f64>的两个变体进行分别处理,None分支返回–,而Some(f64)的内容便是我们真正需要的内容,对其进行格式化

1
2
let result = show_number(Some(0.34));
println!("result={}", result);

接下来对其进行调用,使用Some(T),这里0.34代表的是f64,它会匹配到matchSome分支

image-20230605224410051

最终输出处理的结果34%

3. 匹配必须穷举所有的可能

使用match表达式需要注意,Rust 需要穷举出所有的可能,如果有漏掉的分支,代码编译是无法通过的

image-20230605224816805

image-20230605224845156

4. _ 通配符

使用match匹配的时候,可能我们有很多的分支,但是我们可能只关心其中的几条分支的处理,应该如何处理呢?

1
2
3
4
5
6
7
fn handle_error_code(code: i32) {
match code {
404 => println!("页面缺失"),
500 => println!("服务问题"),
_ => println!("忽略")
}
}

如果我们只关心404和500的错误码,那么其他情形可以统一使用_处理

5. 简单控制流 if let

如果我们只关心match分支的某一种结果,那么if let可以帮到你

如果说我们只关心500的错误码,可以这样写:

1
2
3
4
5
fn handle_error_code(code: i32) {
if let 500 = code {
println!("服务问题")
}
}

使用if let将期望的分支与匹配的值用=关联起来,只对这一种情况进行处理,换言之,这是在追求简洁性的同时放弃了match穷尽性检测,因此具体使用哪个需要自己进行权衡,简洁性和穷尽性检测不可兼得

match中的_对应的还有if let当中的else,它同样是一个兜底的角色

1
2
3
4
5
6
7
fn handle_error_code(code: i32) {
if let 500 = code {
println!("服务问题")
} else { // 兜底
println!("我不关心!")
}
}