写点什么

Rust 从 0 到 1- 枚举 -match 控制流

用户头像
关注
发布于: 2021 年 04 月 16 日
Rust从0到1-枚举-match控制流

match 是 Rust 的一个极为强大的控制流运算符,类似 switch,但 match 更强大,它允许我们将一个值与一系列的“模式”相比较,并根据相匹配的“模式”执行相应代码。“模式”可由文本、变量、通配符等等构成(后面会介绍不同种类的模式以及它们的作用),非常灵活并且编译器还会确保所有可能的情况都做了处理。

可以把 match 想象成某种硬币分类器:硬币会滑入第一个符合它大小的孔洞。同样地,match 也会将值同每一个模式逐个匹配,并且在遇到第一个 “符合” 的模式时,进入相关联的代码块执行。下面我们就用“硬币”作为一个使用 match 的例子!编写一个函数确定“硬币”的种类并返回它的面值:

enum Coin {    Penny,    Nickel,    Dime,    Quarter,}fn value_in_cents(coin: Coin) -> u8 {    match coin {        Coin::Penny => {            println!("Lucky penny!");            1        },        Coin::Nickel => 5,        Coin::Dime => 10,        Coin::Quarter => 25,    }}
复制代码

match 关键字后的表达式(在这个例子中是 coin )看起来和 if 使用的表达式很像,不过它们有一个非常大的区别:对于 if,表达式必须返回一个布尔值,而对于 match, 表达式可以是任何类型的。在执行时,表达式的值将按顺序与每一个分支的“模式”匹配。如果符合,则这个模式相关联的代码将被执行;如果不匹配,就继续执行下一个分支。每个分支执行的结果值将作为整个 match 表达式的返回值。

获取枚举成员关联的值

1999 年到 2008 年间,25 美分的硬币的一侧设计有美国 50 个州的不同图案。假设我们尝试收集所有 50 个州图案的 25 美分硬币,也就说,在根据硬币类型分类的同时,我们也想知道每个 25 美分硬币所对应的州,这样如果我们还没有这个州的话,可以将其加入收藏。那么应该怎么做呢?我们可以将这些信息加入枚举成员里,修改 Quarter 成员来包含一个 State 值;然后,我们在 Coin::Quarter 分支中增加了一个 state 变量,当匹配到 Coin::Quarter 时,变量 state 将会绑定 coin 所对应的州,接着就可以在分支代码中使用 state 进行处理(在例子里我们只是简单的打印出来):


enum UsState { Alabama, Alaska, // --snip--}enum Coin { Penny, Nickel, Dime, Quarter(UsState),}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 }, }}
复制代码

匹配 Option<T>

我们在之前的部分介绍过 Option<T> 的定义,但是没介绍如何使用。比如我们想要编写一个函数,它的参数是 Option<i32> 并且如果其中有值,将其加一;如果其中没有值,返回 None 值并不执行任何操作。我们可以通过 match 非常简单的实现:

fn plus_one(x: Option<i32>) -> Option<i32> {    match x {        None => None,        Some(i) => Some(i + 1),    }}fn main() {  let five = Some(5);  let six = plus_one(five);  let none = plus_one(None);}
复制代码

将 match 与枚举结合使用的场景非常常见。你会在 Rust 代码中看到很多这样的例子:match 一个枚举,绑定其中的值到一个或多个变量,接着在执行代码中使用这些值。根据官方文档的说法,这一直是用户的最爱。

匹配分支是穷尽的

match 还有一个地方需要讨论。参考下面 plus_one 函数的实现,无法编译通过:

fn plus_one(x: Option<i32>) -> Option<i32> {    match x {        Some(i) => Some(i + 1),    }}
复制代码

这是由于代码没有处理 None 的情况,这样的代码可能会产生 bug。Rust 不允许这种情况发生,Rust 知道我们没有覆盖所有可能的情况甚至知道哪些“模式”被忘记了!Rust 要求必须穷举所有可能的“模式”。在这个 Option<T> 的例子中,编译器会提醒我们没有处理 None 的情况,这使我们免于造成之前提到过的价值亿万的错误。

_ 通配符

如果表达式是一个 u32 ,要穷举所有可能的“模式”,我想我们可能要疯了,别着急,Rust 提供了一种方法用于处理这种场景。例如,u8 拥有 0 到 255 的 256 个值,如果我们只关心 1、3、5 和 7 这几个值,那其余的值可以使用通配符 _ 替代(类似 swith 里的 default):

let some_u8_value = 0u8;match some_u8_value {  1 => println!("one"),  3 => println!("three"),  5 => println!("five"),  7 => println!("seven"),  _ => (),}
复制代码

可以匹配任何值。通过将其放置于其他分支之后,_ 将会匹配所有之前没有指定的值。在例子中 _ 返回 () ,即 unit 类型(在前面讲结构体的时候提到过),也就是说对其余的值不做任何处理,也不返回任何有意义的值。

发布于: 2021 年 04 月 16 日阅读数: 11
用户头像

关注

公众号"山 顽石"欢迎大家关注;) 2021.03.23 加入

IT老兵,关注Rust、Java、前端、架构、大数据、AI、算法等;平时喜欢美食、旅游、宠物、健身、篮球、乒乓球等。希望能和大家交流分享。

评论

发布
暂无评论
Rust从0到1-枚举-match控制流