Skip to content

6. Rust 枚举与模式匹配

6.1 定义枚举

枚举(Enum)是一种类型,它允许你定义一个类型可以是多个不同的变体之一。枚举的变体称为 枚举成员(Enum Member)。

rust
enum IpAddrKind {
    V4,
    V6,
}

创建枚举实例:

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

枚举不同的变体可以包含不同的数据类型和关联数据。例如:

rust
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

使用:

rust
#[derive(Debug)]
enum IpAddrKind {
    V4(u8, u8, u8, u8),
    V6(String),
}

fn main() {
    let home = IpAddrKind::V4(127, 0, 0, 1);
    let loopback = IpAddrKind::V6(String::from("::1"));

    println!("home: {:?}", home);
    println!("loopback: {:?}", loopback);
}

还可以为枚举实现方法:

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

impl Message {
    fn call(&self) {
        // method body would be defined here
        println!("call")
    }
}
fn main() {
    let msg = Message::Write(String::from("hello"));
    let msg2 = Message::ChangeColor(0, 0, 0);
    let msg3 = Message::Move { x: 0, y: 0 };
    let msg4 = Message::Quit;
    msg.call();
}

其中 Move 成员包含了一个匿名结构体,Write 成员包含了一个 StringChangeColor 成员包含了三个 i32 值。

6.2 Option 枚举

Option 是标准库中定义的一个枚举,它有两个变体:SomeNone。其位于预导入库中,可直接使用。

Rust 中没有 Null 值,Rust 提供了 Option<T> 来处理可能为 null 的情况。其定义如下:

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

使用:

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

Option<T>T 是不同的类型,我们使用时必须将其转换为相同的类型。可以使用 unwrap 方法来获取 Option<T> 中的值,如果 Option<T>Noneunwrap 会导致 panic。

rust
fn main() {
    let some_number = Some(5);
    let number = 5;
    let sum = number + some_number.unwrap_or(0);
    println!("sum: {}", sum);
}

6.3 match 控制流

match 是 Rust 中的一个关键字,它允许我们将一个值与一系列模式进行比较,并根据匹配的模式执行相应的代码。

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

绑定值的模式:

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

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

fn main() {
    let c = Coin::Quarter(UsState::Alaska);
    println!("{}", value_in_cents(c));
}

同理,Option<T> 也可以使用 match

rust
fn main() {
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
    println!("{:?}", six);
    println!("{:?}", none);
}

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

match 匹配必须穷举所有可能的情况,否则编译器会报错。可以使用 _ 通配符来匹配所有其他情况。

rust
fn main() {
    let some_u8_value = 0u8;
    match some_u8_value {
        1 => println!("one"),
        3 => println!("three"),
        5 => println!("five"),
        7 => println!("seven"),
        _ => (),
    }
}

6.4 if let

if let 语法允许我们只匹配一个模式,而忽略其他模式。if let 语法适用于只关心一个模式的情况,而不关心其他情况。

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

if let 表达式可以和 else 一起使用:

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

这类似于 match 语句,但是更简洁。