Rust 具备一个十分弱小的控制流运算符,称为 match,它使咱们能够将值与一系列模式进行比拟,而后依据匹配的模式执行代码。模式能够由文字值,变量名,通配符和许多其余内容组成。个人感觉跟 js 外面的 switch 一样~^~
介绍该点的 rust 的教程给了一个十分有意思的比喻:能够将匹配表达式想像成硬币分类机:硬币沿着轨道滑动,轨道上有各种大小的孔,每枚硬币都从遇到的第一个孔中掉落。以雷同的形式,值在匹配中遍历每个模式,并且在第一个模式中值“适宜”,该值落入要在执行期间应用的关联代码块。
match 用法样例:
use crate::Coin::Penny;
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
fn main() {println!("{}", value_in_cents(Penny))
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
warning: variant is never constructed: `Nickel`
--> src\main.rs:5:5
|
5 | Nickel,
| ^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: variant is never constructed: `Dime`
--> src\main.rs:6:5
|
6 | Dime,
| ^^^^
warning: variant is never constructed: `Quarter`
--> src\main.rs:7:5
|
7 | Quarter,
| ^^^^^^^
warning: 3 warnings emitted
Finished dev [unoptimized + debuginfo] target(s) in 1.03s
Running `target\debug\cargo_learn.exe`
1
目前为止除了写法不统一之外,跟 js 外面的 switch 还没有任何区别
绑定到值的模式
match 的另一个有用性能是它们能够绑定到与模式匹配的局部值。这就是咱们能够从枚举变量中提取值的形式。
举例来说,更改其中一个枚举变量以将数据保留在其中。从 1999 年到 2008 年,美国为一侧的 50 个州铸造了不同设计的宿舍。没有其余硬币取得国家设计,因而只有四分之一硬币具备这种额定价值。能够通过将 Quarter 变体更改为蕴含在其中的 UsState 值来将其增加到枚举中,如下例所示:
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
// --snip--
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
假如咱们的一个敌人正在尝试收集所有 50 个州的宿舍。在按硬币类型对零钱进行分类的同时,咱们还将标注与每个季度相干的州的名称,因而,如果这是咱们敌人所没有的状态,他们能够将其增加到他们的珍藏中。
在此代码的 match 表达式中,咱们向模式增加一个名为 state 的变量,以匹配变体 Coin::Quarter 的值。当 Coin::Quarter 匹配时,状态变量将绑定到该季度状态的值。而后,咱们能够在代码中为该支路应用状态,如下所示:
#[derive(Debug)]
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);
25
}
}
}
fn main() {value_in_cents(Coin::Quarter(UsState::Alaska));
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
warning: variant is never constructed: `Alabama`
--> src\main.rs:3:5
|
3 | Alabama,
| ^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: variant is never constructed: `Penny`
--> src\main.rs:9:5
|
9 | Penny,
| ^^^^^
warning: variant is never constructed: `Nickel`
--> src\main.rs:10:5
|
10 | Nickel,
| ^^^^^^
warning: variant is never constructed: `Dime`
--> src\main.rs:11:5
|
11 | Dime,
| ^^^^
warning: 4 warnings emitted
Finished dev [unoptimized + debuginfo] target(s) in 0.50s
Running `target\debug\cargo_learn.exe`
地址来自 Alaska!
与 Option <T> 匹配
假如咱们要编写一个应用 Option <i32> 的函数,并且如果其中蕴含一个值,则将该值加 1。如果外部没有值,则该函数应返回 None 值,并且不要尝试执行任何操作。
借助 match,该函数十分易于编写,相似于下例:
fn main() {fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
println!("{:?}", five);
println!("{:?}", six);
println!("{:?}", none);
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.53s
Running `target\debug\cargo_learn.exe`
Some(5)
Some(6)
None
深度比拟
咱们还须要探讨 match 的另一方面。思考咱们的 plus_one 函数的此版本存在谬误并且无奈编译:
fn main() {fn plus_one(x: Option<i32>) -> Option<i32> {
match x {Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}
D:\learn\cargo_learn>cargo run
error[E0004]: non-exhaustive patterns: `None` not covered
--> src/main.rs:3:15
|
3 | match x {
| ^ pattern `None` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error: aborting due to previous error
For more information about this error, try `rustc --explain E0004`.
error: could not compile `enums`.
To learn more, run the command again with --verbose.
Rust 晓得咱们没有涵盖所有可能的状况,甚至晓得咱们遗记了哪种模式!Rust 中的匹配十分详尽:为了使代码无效,咱们必须尽所有可能。特地是在 Option <T> 的状况下,当 Rust 阻止咱们遗记显式解决 None 状况时,它能够避免咱们假如咱们有可能为 null 的值。
_占位符
当咱们不想列出所有可能的值时,Rust 也能够应用一种模式。例如,一个 u8 能够具备 0 到 255 的有效值。如果咱们只关怀值 1、3、5 和 7,咱们就不用列出 0、2、4、6、8、9 始终到 255。侥幸的是,咱们能够应用非凡模式_代替:
fn main() {
let some_u8_value = 0u8;
match some_u8_value {1 => println!("one"),
3 => println!("three"),
5 => println!("five"),
7 => println!("seven"),
_ => (println!("啥也不是")),
}
}
D:\learn\cargo_learn>cargo run
Compiling cargo_learn v0.1.0 (D:\learn\cargo_learn)
Finished dev [unoptimized + debuginfo] target(s) in 0.50s
Running `target\debug\cargo_learn.exe`
啥也不是
_模式将匹配任何值。将_放在咱们的其余特定指标之后,它将匹配之前未指定的所有可能状况。()只是单位值,因而在_状况下什么也不会产生。后果,咱们能够说咱们不想对未在_占位符之前列出的所有可能值做任何事件。
然而,在咱们只关怀其中一种状况的状况下,match 表达式可能有点繁琐。对于这种状况,Rust 提供了if let
。