Skip to content

枚举

允许我们列举所有可能的值来定义一个类型,比如性别:要么是男、要么是女(人妖:???),这就是一种枚举类型

rust
enum Gender {
	Boy,
	Girl,
}

枚举值

rust
enum Gender {
	Boy,
	Girl,
}
// 枚举的变体都位于标识符的命名空间下,使用两个冒号分隔开
let boy = Gender::Boy;
let girl = Gender::Girl;

将数据附加到枚举的变体中

rust
enum Gender {
    Boy(String),
    Girl(String),
}

// 或者
enum Gender {
    Boy(String, String, String),
    Girl(String),
}

fn main() {
    let boy = Gender::Boy( "大锤", "中风", "小明");
    let girl = Gender::Girl("小红");
}
  • 优点:不需要使用额外的结构体 struct
  • 每个变体都可以拥有不同(任意)的类型以及关联的数据量
rust
#[derive(Debug)]
enum Gender {
    Boy(String, String, String),
    Girl(String),
}

fn main() {
    let boy1 = String::from("大锤");
    let boy2 = String::from("中风");
    let boy3 = String::from("小明");
    let girl1 = String::from("小红");

    let boy = Gender::Boy(boy1, boy2, boy3);
    let girl = Gender::Girl(girl1);

    // boys are: Boy("大锤", "中风", "小明"), girl is: Girl("小红")
    println!("boys are: {:?}, girl is: {:?}", boy, girl);
}

为枚举定义方法

类似于给结构体定义方法,使用 impl 关键字。

rust
enum Gender {
    Boy(String, String, String),
    Girl(String),
}

impl Gender {
    fn run(&self, gender: String) {
        println!("{} 跑得很快", gender);
    }
}

fn main() {
    let boy1 = String::from("大锤");
    let boy2 = String::from("中风");
    let boy3 = String::from("小明");
    let girl1 = String::from("小红");

    let boys = Gender::Boy(boy1, boy2, boy3);
    let girl = Gender::Girl(girl1);

    boys.run(String::from("男孩们")); // 男孩们 跑得很快
    girl.run(String::from("小女孩")); // 小女孩 跑得很快
}

Option 枚举

  • 定义在标准库中
  • 在 prelude(预导入模块)中,不需要用户手动导入
  • 描述了某个值可能存在或不存在的情况

Rust 中没有 Null(表示没有值)这个概念,Null 的概念实际上是因为某种原因变为无效或缺失的值,那么 Rust 使用什么代替呢?

Rust 提供了类似于 Null 概念的枚举 Option<T>,T 是泛型,泛型的用法类似于其它语言,后面具体讲。

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

看个例子

rust
fn main() {
    let x: i8 = 5;
    let y: Option<i8> = Some(5);
    let z: Option<i8> = None;

    // 报错cannot add `std::option::Option<i8>` to `i8`
    let sum = x + y;
}

在这里,Option<i8>和 i8 是两个不同的类型,不可以直接相加,比 Null 来说更安全。

枚举和模式匹配的控制流运算符 match

这是现代化语言的精髓部分

  • 允许一个值和一系列模式进行匹配,并执行匹配的模式对应的代码
  • 模式可以是字面值、变量名、通配符
rust

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

enum Coin {
    Penny,            // 一便士
    Nickel,           // 五美分
    Dime,             // 十美分
    Quarter(UsState), // 二十五美分
}

fn value_in_coin(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("美国的{:?}州用的25美分硬币", state); // 美国的Sanfrancisco州用的25美分硬币
            25
        }
    }
}

fn main() {
    let q = Coin::Quarter(UsState::Sanfrancisco);
    println!("{}", value_in_coin(q)); //25
}

match 必须穷举所有可能的值

rust
fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        // 如果不加None的模式匹配就会报错,必须穷举所有可能的值
        None => None,
        Some(i) => Some(i + 1),
    }
}

fn main() {
    let one = Some(1);
    let two = plus_one(one);
    let none = plus_one(None);
}

如果不想列出所有可能的值时可以使用 _ (下划线)通配符,替代其它没列出的值

rust
fn plus_one(x: Option<i32>) -> Option<i32> {
    // 不需要穷举所有的可能性了,全部默认返回Some(0)
    match x {
        _ => Some(0),
    }
}

fn main() {
    let one = Some(1);
    let two = plus_one(one);
    let none = plus_one(None);
}

if let

处理只关心一种匹配而忽略其它匹配的情况

rust
fn main() {
    let v = Some(0u8);

    match v {
        Some(3) => println!("3"),
        _ => (), // 什么也不做
    }

    // 这两段代码效果完全一致,if let 只关心一种模式匹配,但是放弃了穷举的可能,可以看作是match的语法糖
    if let Some(3) = v {
        println!("3");
    }
}

也可以使用 else 来进行其它可能性的返回

rust
fn main() {
    let v = Some(0u8);

    match v {
        Some(3) => println!("3"),
        _ => println!("others"),
    }

    if let Some(3) = v {
        println!("3");
    } else {
        println!("others");
    }
}

每天进步一丢丢