乐趣区

关于rust:rust学习匹配控制流运算符match

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

退出移动版