Rust 中的Match控制模式

149 阅读3分钟

Match控制模式在很多语言都有相同的特性,Rust的特别之处在于Match模式和EnumOption搭配使用产生的效果。

基本用法

如果匹配到的代码块比较简短,可以不用使用大括号,并且以逗号分隔。如果比较长,那么就需要使用大括号,并且逗号分隔符可以省略。

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() {
	let p = Coin::Penny;
	let n = Coin::Nickel;
	value_in_cents(p);
	value_in_cents(n);
}

上述代码中,value_in_cents的参数类型是Coin,而Coin的子类型的变量也可以作为value_in_cents的入参。之前说过,Enum可以理解为一组子类型的集合,所有子类型都可以代表父类型。所以任何一个子类型变量,都可以作为 value_in_cents 的参数。

使用大括号的情况:

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

绑定参数

Enum是可以添加类型的,Match的各个匹配项可以将Enum绑定的类型作为匹配项的参数。

#[derive(Debug)] // so we can inspect the state in a minute
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    // 这里添加了一个Enum类型
    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
        }
    }
}

fn main() {
	let u = Coin::Quarter(UsState::Alabama);
	
	value_in_cents(u);
}

上面代码中,UsState::Alabama 就成了 Coin::Quarter(state) 中的参数 state。

Match模式与Option搭配使用

Match模式与Option搭配使用,就能够实现非空判断。

我们尝试实现一个函数,包含逻辑:如果参数不为空,就+1,如果为空,就不做任何操作。

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);
}

plus_one函数就实现了这个功能。值得注意的是,match中的每个分支都使用了不带;函数return语句

使用Match模式的规则

第一个规则:Match需要覆盖所有的可能。

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);
}

以上代码没有处理None的情况,所以编译会报错。

第二个规则:可以实现类似Default的效果。

如果需要变量的值,可以使用任意一个变量名来替代,比如:

fn main() {
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            Some(i) => Some(i + 1),
            a => a,
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
}

如果不需要变量的值,可以使用 _ 来表示

fn main() {
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            Some(i) => Some(i + 1),
            _ => temp(),
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
	
	fn temp(){}
}

如果分支后面不需要执行任何代码

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

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}
}

以上是Match模式匹配变量的例子