Enums 枚举

枚举:定义单一类型,但只能是若干种不同变体 (variant) 其中之一

枚举变体支持三种形式:单元变体、元组结构体变体、命名结构体变体。

以前学的其他编程语言 C C++ JAVA C#等等,枚举的值都只有一种类型 整数,但是rust中,枚举还可以是元组 结构体,同时配合match,不仅仅可以完成匹配,还可以把匹配的值解构

基础定义

// 允许未使用代码,消除所有dead_code系列警告
#![allow(dead_code)]

// 枚举定义:WebEvent,代表网页事件
enum WebEvent {
    // 1. 单元式变体(类似单元结构体,不带任何数据)
    PageLoad,
    PageUnload,
    // 2. 元组变体(类似元组结构体,携带有序数据)
    KeyPress(char),
    Paste(String),
    // 3. 命名字段变体(类似C风格结构体,具名字段)x y 表示点击坐标点
    Click { x: i64, y: i64 },
}

fn main() {
    // 构造不同枚举实例
    let load = WebEvent::PageLoad;
    let key = WebEvent::KeyPress('k');
    let paste = WebEvent::Paste("hello".to_owned());
    let click = WebEvent::Click { x: 10, y: 20 };
}Code language: Rust (rust)

知识点解析

  1. 枚举名称::变体名 是完整标识:WebEvent::KeyPress
  2. 三大变体:
    • 单元变体:无附加数据 PageLoad
    • 元组变体:带括号、有序数据 KeyPress(char)
    • 结构体变体:大括号、命名字段 Click{x,y}
  3. 重点:不同变体是完全独立类型 WebEvent::PageLoadWebEvent::PageUnload WebEvent::KeyPress(char)WebEvent::Paste(String) 虽然同属 WebEvent 枚举,但携带数据结构不一样。
  4. to_owned():把字符串字面量 &str 转换成拥有所有权的 String,满足枚举变体所有权要求。

匹配枚举和枚举变体

// 允许未使用代码,消除所有dead_code系列警告
#![allow(dead_code)]

enum WebEvent {
    PageLoad,
    PageUnload,
    KeyPress(char),
    Paste(String),
    Click { x: i64, y: i64 },
}

// match 处理枚举,同时解构变体内部数据
fn inspect(event: WebEvent) {
    match event {
        // 单元变体:直接匹配
        WebEvent::PageLoad => println!("页面加载"),
        WebEvent::PageUnload => println!("页面关闭"),
        // 元组变体解构:取出括号内的值绑定变量 c
        WebEvent::KeyPress(c) => println!("按下按键:{}", c),
        WebEvent::Paste(s) => println!("粘贴内容:{}", s),
        // 结构体变体解构:提取命名字段 x,y
        WebEvent::Click { x, y } => println!("点击坐标 x={},y={}", x, y),
    }
}

fn main() {
    let pressed = WebEvent::KeyPress('x');
    let pasted  = WebEvent::Paste("my text".to_owned());
    let click   = WebEvent::Click { x: 20, y: 80 };
    let load    = WebEvent::PageLoad;
    let unload  = WebEvent::PageUnload;

    inspect(pressed);
    inspect(pasted);
    inspect(click);
    inspect(load);
    inspect(unload);
}
Code language: Rust (rust)
  1. match 是处理枚举最核心语法,要求穷尽所有变体(必须覆盖全部分支,否则编译报错)
  2. 枚举解构规则(和 struct/tuple 解构思想统一)
    • 单元变体:无需解构,直接匹配
    • 元组变体:WebEvent::KeyPress(c) 将内部 char 绑定给变量 c
    • 结构体变体:WebEvent::Click{x,y} 直接提取字段为变量
  3. 解构会获取变体内部数据的所有权
  4. match 每个分支使用 =>,分支代码多行需要大括号 {}

Type Alias 类型别名

// 允许未使用代码,消除所有dead_code系列警告
#![allow(dead_code)]

// 定义原始枚举(名字很长)
enum VeryVerboseEnumOfThingsToDoWithNumbers {
    Add,
    Subtract,
}

// 类型别名:给长类型起简短名字
type Operations = VeryVerboseEnumOfThingsToDoWithNumbers;

fn main() {
    // 可以直接使用别名::变体
    let calc = Operations::Add;
    // 原始写法依然合法,两种写法等价
    let calc2 = VeryVerboseEnumOfThingsToDoWithNumbers::Subtract;
}

Code language: Rust (rust)

知识点解析

  1. 语法:type 别名 = 原有类型;
  2. 类型别名不会创建新类型!仅仅是缩写、别名 OperationsVeryVerboseEnumOfThingsToDoWithNumbers 是同一个类型,完全互通
  3. 使用场景:原始类型名称太长、泛型类型繁琐,简化代码书写

impl 中 Self 别名

enum VeryVerboseEnumOfThingsToDoWithNumbers {
    Add,
    Subtract,
}

// 为枚举实现方法
impl VeryVerboseEnumOfThingsToDoWithNumbers {
    // &self 代表当前枚举实例的引用
    fn run(&self, x: i32, y: i32) -> i32 {
        match self {
            // Self 等价于 VeryVerboseEnumOfThingsToDoWithNumbers
            Self::Add => x + y,
            Self::Subtract => x - y,
        }
    }
}

fn main() {
    let op = VeryVerboseEnumOfThingsToDoWithNumbers::Add;
    println!("{}", op.run(10, 5));

    let op2 = VeryVerboseEnumOfThingsToDoWithNumbers::Subtract;
    println!("{}", op2.run(10, 5));
}
Code language: PHP (php)

  1. impl 类型 {} 代码块内部,Self 是内置类型别名,代表当前正在实现方法的类型
  2. 好处:
    • 枚举 / 结构体名字很长时,不用反复抄写完整名称
    • 后续修改原始类型名称,impl 内部代码无需改动
  3. &self:方法借用枚举实例,不获取所有权,调用之后实例依然有效

区别

  1. struct:一个实例同时拥有全部字段
  2. enum:一个实例只能是众多变体里的其中一种,互斥
  • 结构体:Point{x,y}
  • 元组结构体:Pair(a,b)
  • 枚举元组变体:WebEvent::KeyPress(c)
  • 枚举结构体变体:WebEvent::Click{x,y}

所有解构底层逻辑一致:匹配数据结构,把内部数据提取绑定到独立变量

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注