RUA!

Rust 模式匹配

TABLE OF CONTENTS

match

match 是一个极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成。

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

绑定值的模式

在匹配到绑定值的模式后,可以增加一个变量用来表示所匹配到的值。

#[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 quarter from {:?}!", state);
            25
        }
    }
}

这里的 Coin::Quarter(state) 就是匹配到的对应的 UsState 的值。

匹配 Option

fn plus_one(target: Option<i32>) -> Option<i32> {
    match target {
        Some(x) => Some(x + 1),
        None => None,
    }
}

fn main() {
    let my_num = Some(41);
    let my_num = plus_one(my_num);
    println!("My number: {:?}", my_num);
}

这里 Clippy 可能会提示我们有更好的写法:

fn plus_one(target: Option<i32>) -> Option<i32> {
    target.map(|x| x + 1);
    target
}

fn main() {
    let my_num = Some(41);
    let my_num = plus_one(my_num);
    println!("My number: {:?}", my_num);
}

Option<T> 上有个 map() 方法,可以更好的代替 match Option 来做匹配。

穷尽的匹配

match 的匹配是穷尽的,必须穷举到最后的可能性来使代码有效。

但可以使用一个特定值来采取默认操作,有点类似于 switch 语句中的 default

let dice_roll = 9;
match dice_roll {
    3 => add_fancy_hat(),
    7 => remove_fancy_hat(),
    _ => (),
}

这个例子也满足穷举性要求,因为我们在最后一个分支中明确地忽略了其他的值。我们没有忘记处理任何东西。

if let

为了满足 match 的穷尽性的要求,必须穷举到所有的可能性。尽管可以使用默认操作,但是最少也需要两行语句。

fn main() {
    let config_max = Some(3u8);
    match config_max {
        Some(config) => println!("The maximum is configured to be {}", config),
        _ => (),
    }
}

不过我们可以使用 if let 这种更短的方式编写。

fn main() {
    let config_max = Some(3u8);

    if let Some(config) = config_max {
        println!("The maximum is configured to be {}", config);
    }
}

如果使用了 Clippy 这里也会提示我们可以使用更短的写法。

if let 语法获取通过等号分割的一个模式和一个表达式。它的工作方式与 match 相同。这里等号右边的表达式对应着 match ,而左边的模式对应着 match 的第一个分支。

在这个例子中,模式是 Some(max)max 绑定为 Some 中的值。接着可以在 if let 代码块中使用 max 了,就跟在对应的 match 分支中一样。模式不匹配时 if let 块中的代码不会执行。

换句话说,可以认为 if let 是 match 的一个语法糖,它当值匹配某一模式时执行代码而忽略所有其他值。