枚举与匹配模式

2023/3/11

# 枚举

定义枚举

enum IpAddrKind {
    V4,
    V6,
}

枚举值

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

使⽤结构体来存储 IP 地址的数据和 IpAddrKind 变体

enum IpAddrKind {
    V4,
    V6,
}

struct IpAddr {
    kind: IpAddrKind,
    address: String,
}

fn main() {
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;
    let home = IpAddr {
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };

    let loopback = IpAddr {
        kind: IpAddrKind::V6,
        address: String::from("::1"),
    };
}

枚举嵌入各种数据

Quit 没有任何关联数据

Move 包含了⼀个匿名结构体

Write 包含了⼀个 String。

ChangeColor 包含了 3 个 i32 值。

enum Message {
    Quit,
    Move {x:i32,y:i32},
    Write(String),
    ChangeColor(i32,i32,i32)
}

// 相同结构
struct QuitMessage; // 空结构体
struct MoveMessage {
    x: i32,
    y: i32,
}
struct WriteMessage(String); // 元组结构体
struct ChangeColorMessage(i32, i32, i32); // 元组结构体

定义枚举方法

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

impl Message {
    fn call(&self) {
        // 方法体
    }
}

fn main() {
    let m = Message::Write(String::from("hello"));
    m.call();
}

# 控制流运算符 match

常强⼤的控制流运算符:match,它允许将⼀个值与⼀系列的模式相⽐较,并根据匹配的模式执⾏相应代码。

#[derive(Debug)]
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

fn main() {
    let penny = Coin::Penny;
    // Coin::Penny 被匹配成功,返回1
    print!("coin{}\n", value_in_cents(penny)); // coin1
}

绑定值的模式(匹配括号中的值)

#[derive(Debug)]

enum UsState {
    Alabama,
    Alaska,
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState), // Quarter 变体存放了一个UsSate值
}

fn value_in_cents(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            // 打印state的值
            println!("State quarter from {:?}!", state);
            25
        }
    }
}

fn main() {
    let quarter = Coin::Quarter(UsState::Alabama);
    println!("coin{}", value_in_cents(quarter))
}

// 输出
// State quarter from Alabama!
// coin25

匹配 Option<T>

想要编写⼀个接收 Option的函数,如果其中有值存在,则将这个值加 1。如果其中不存在值,那么这个函数就直接返回 None ⽽不进⾏任何操作

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

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

    println!("six:{:?}", six);    // six:Some(6)
    println!("none:{:?}", none)   // none:None
}

匹配必须穷举所有的可能

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

因为没有穷举所有的可能性编译报错,Rust 知道我们没有覆盖所有可能的情形,甚⾄能够确切地指出究竟是哪些模式被我们漏掉了!Rust 中的匹配是穷尽的(exhausitive):我们必须穷尽所有的可能性,来确保代码是合法有效的。特别是在这个 Option的例⼦中,Rust 会强迫我们明确地处理值为 None 的情形。

error[E0004]: non-exhaustive patterns: `None` not covered
 --> main.rs:4:11
  |
4 |     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`.

_通配符

不想匹配所有情况

let some_u8_value = 0u8;
match some_u8_value {
    1 => println!("one"),
    3 => println!("three"),
    _ => (), // 匹配剩余的其他值,没必要列出0~255的所有值
}

简单控制流 if let

示例一

fn main() {
    let some_u8_value = Some(3);

    // 示例一等于3时执行
    match some_u8_value {
        Some(3) => println!("three"),
        _ => (),
    }

    // if let实现
    if let Some(3) = some_u8_value {
        println!("three");
    }
}

示例二(match 方式)

#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState), // Quarter 变体存放了一个UsSate值
}

fn main() {
    // 示例二 如果是Quarter就打印,否则count 加一
    let mut count = 0;
    let coin = Coin::Penny;
    match coin {
        Coin::Quarter(state) => println!("state quarter from {:?}!", state),
        _ => count += 1,
    }

    println!("count:{}", count); // count:1
}

示例二(if else)

#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState), // Quarter 变体存放了一个UsSate值
}

fn main() {
    // 示例二 如果是Quarter就打印,否则count 加一
    let mut count = 0;
    let coin = Coin::Penny;

    if let Coin::Quarter(state) = coin {
        println!("state quarter from {:?}!", state)
    } else {
        count += 1;
    }

    println!("count:{}", count); // count:1
}