枚举和模式匹配

枚举和模式匹配

1.枚举

1.1 定义枚举

fn main() {
    enum Message {
        Quit, // 没有关联任何数据
        Move { x: i32, y: i32 }, // 包含一个匿名结构体
        Write(String), // 包含单独一个 String
        ChangeColor(i32, i32, i32), // 包含三个 i32
    }
}

使用struct定义👆枚举中的成员

fn main() {
    struct QuitMessage; // 类单元结构体
    struct MoveMessage {
        x: i32,
        y: i32,
    }
    struct WriteMessage(String); // 元组结构体
    struct ChangeColorMessage(i32, i32, i32); // 元组结构体
}

1.2 为枚举定义方法

fn main() {
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }
    
    impl Message {
        fn call(&self) {
            // 在这里定义方法体
        }
    }
    
    let m = Message::Write(String::from("hello"));
    m.call();
}

1.3 Option

定义在标准库如下:

enum Option<T> {
    Some(T),
    None,
}

使用Option

fn main() {
    let some_number = Some(5);
    let some_string = Some("a string");
    
    let absent_number: Option<i32> = None;
}

2.match 控制流

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,
    }
}

2.1 绑定值的模式

匹配分支的另一个功能是可以绑定匹配模式的部分值,即从枚举成员中提取值。

#[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
        }
    }
}

2.2 匹配Option<T>

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

2.3 ⚠️ 匹配是穷尽的

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x { // error[E0004]: non-exhaustive patterns: `None` not covered
        Some(i) => Some(i + 1),
    }
}

没有处理None的情况,会造成bug

2.4 通配模式和_占位符

对一些特定的值采取特殊操作,而对其它值采取默认操作。

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

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}
    fn move_player(num_spaces: u8) {}
}

当不想使用通配模式获取值时,使用_,可以匹配任意值而不绑定到该值,告诉Rust不会使用这个值。

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() {}
}

3.if let 控制流

处理匹配一个模式的值而忽略其它模式的情况。

fn main() {
    let some_u8_value = Some(0u8);
    match some_u8_value {
        Some(3) => println!("three"),
        _ => (),
    }
}

修改为

fn main() {
    let some_u8_value = Some(0u8);
    if let Some(3) = some_u8_value {
        println!("three");
    }
}

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

可以在if let中包含一个elseelse块中的代码与match表达式中的_分支块中的代码相同,这样的match表达式就等同于if letelse

fn main() {
    let mut count = 0;
    if let Coin::Quarter(state) = coin {
        println!("State quarter from {:?}!", state);
    } else {
        count += 1;
    }
}
最后更新于