控制流 match 和 if let
rust 中有一个强大的控制流运算符:match,它允许将一个值与一系列的模式相比较,并根据匹配的模式执行相应代码,模式可由字面量、变量名、通配符和许多其他东西组成(后面章节会详细介绍)。
match 的简单使用
我们将创建一个包含 3 中 web 框架的枚举,根据枚举变体类型获取框架最新版本号:
// 定义一个框架枚举,包含3种框架的变体
enum Framework {
Vue,
Angular,
React
}
fn framework_version(framework: Framework) -> u32 {
// 使用match关键字对framework进行匹配
match framework {
// 模式 => 处理逻辑
Framework::Vue => 3,
Framework::Angular => 12,
Framework::React => { // 多行代码可以添加花括号
return 17
},
}
}
println!("Vue: {}", framework_version(Framework::Vue)); // 3
println!("Angular: {}", framework_version(Framework::Angular)); // 12
println!("React: {}", framework_version(Framework::React)); // 17
复制代码
绑定值的模式
match 还可以绑定被匹配对象的部分值,而这也正是我们用于从枚举变体中提取值的方法:
#[derive(Debug)]
enum VueState { // Vue框架的状态
Stable,
Next,
}
enum Framework {
Vue(VueState), // Vue框架变体关联一个状态类型
Angular,
React
}
fn framework_version(framework: Framework) -> u32 {
match framework {
Framework::Angular => 12,
Framework::React => 17,
Framework::Vue(state) => { // 首先匹配到Vue分支,然后将Next绑定到state上
match state { // 继续匹配state
VueState::Stable => 2,
VueState::Next => 3,
}
}
}
}
// 创建不同状态的Vue枚举
let vue2 = Framework::Vue(VueState::Stable);
let vue3 = Framework::Vue(VueState::Next);
println!("{}", framework_version(vue2)); // 2
println!("{}", framework_version(vue2)); // 3
复制代码
匹配 Option<T>
上一章节中介绍过的 Option<T>,match 也可以将 Option::Some(T)中的 T 值取出:
fn unwrap(x: Option<i32>) -> i32 {
match x {
Option::None => 0, // 当是变体None时,返回0
Option::Some(num) => { // five匹配到Some分支,然后将5匹配到num上
num
},
}
}
let option_five = Option::Some(5);
let five = unwrap(option_five);
let zero = unwrap(None);
println!("{:?}", option_five); // Some(5)
println!("{}", five); // 5
println!("{}", zero); // 0
复制代码
匹配必须穷举的所有可能
如果没有穷举(exhaustive)所有值,将会编译失败:
match framework {
Framework::Vue => 3,
Framework::Angular => 12,
// 报错,Framework::React 情况未覆盖
}
复制代码
_通配符
有的时候,我们可能并不想要处理所有可能的值,rust 同样也提供了一种模式用于处理这种需求:
let some_u8_value = 10u8;
match some_u8_value {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
// 因为u8有255中可能,我们肯定不会穷举所有,只列出关心的即可,其他的用_代替
_ => println!("other")
}
// "other"
复制代码
if let 语法糖
由于 match 的穷举性要求,当我们只关心某一种情况时,代码写起来还是比较繁琐,这时我们可以使用 if let 语法糖来解决:
let some_u8_value = Option::Some(3u8);
// match方式
match some_u8_value {
Option::Some(3u8) => println!("three"),
_ => println!("other")
}
// "three"
// if let方式
if let Option::Some(3) = some_u8_value {
println!("three")
} else {
// else是可选的,相当于match分支中的 _ => println!("other")
println!("other")
}
// "three"
复制代码
我们再看一下最上边 web 框架的例子,使用 if let 代替 match:
let vue2 = Framework::Vue(VueState::Stable);
let vue3 = Framework::Vue(VueState::Next);
// match方式
match vue2 {
Framework::Vue(state) => {
println!("{:?}", state)
}
_ => println!("other")
}
// Stable
// if let方式
if let Framework::Vue(state) = vue3 {
println!("{:?}", state)
} else {
println!("other")
}
// Next
复制代码
评论