Rust 枚举 (enum) 完整核心知识点

Rust 枚举 (enum) 完整核心知识点

涵盖 :基础定义、match 匹配、内存布局、递归枚举、易错点等

特点:由浅入深,含易错点、内存、递归、匹配


目录

  1. 基础定义:枚举是什么
  2. 枚举值创建与使用
  3. 核心:match 模式匹配(#三核心 match 模式匹配)
  4. 枚举绑定值所有权规则
  5. 枚举内存布局
  6. 判别式 discriminant(#六判别式 discriminant)
  7. 常用标准库枚举
  8. 枚举实现方法 impl(#八枚举实现方法 impl)
  9. 模式匹配进阶语法
  10. [枚举 vs 结构体核心区别](#枚举 vs 结构体核心区别 "#%E5%8D%81%E6%9E%9A%E4%B8%BE-vs-%E7%BB%93%E6%9E%84%E4%BD%93%E6%A0%B8%E5%BF%83%E5%8C%BA%E5%88%AB")
  11. 高频易错点总结
  12. 速记口诀

一、基础定义:枚举是什么

枚举是自定义类型,一组互斥的变体,一个枚举实例同一时间只能是其中一种变体。

C 枚举仅数字,Rust 枚举强大在于:每个变体可以附带数据(单元、元组、结构体)。

三种变体写法

rust 复制代码
// 1. 单元变体(无数据,类似 C 枚举)
enum Color { Red, Green, Blue }

// 2. 元组变体(带多个不同类型数据)
enum Msg {
    Quit,              // 单元
    Move(i32, i32),    // 元组
    Write(String),
}

// 3. 结构体变体(命名字段)
enum FileEvent {
    Read { path: String, offset: u64 },
    Write { path: String, data: Vec<u8> },
}

二、枚举值创建与使用

rust 复制代码
let r = Color::Red;
let m = Msg::Move(10, 20);
let w = Msg::Write("hello".to_string());

let ev = FileEvent::Read {
    path: "/tmp/a.txt".into(),
    offset: 0
};

三、核心:match 模式匹配(枚举灵魂)

match 强制覆盖所有变体,无遗漏编译报错,穷尽检查。

rust 复制代码
fn print_msg(msg: Msg) {
    match msg {
        Msg::Quit => println!("退出"),
        Msg::Move(x, y) => println!("移动 {} {}", x, y),
        Msg::Write(s) => println!("写入:{}", s),
    }
}

简化匹配 if let

只关心某一个变体,不想写全 match:

rust 复制代码
if let Msg::Write(text) = m {
    println!("{}", text);
}
// 对应 while let 循环匹配迭代器枚举

四、枚举绑定值所有权规则

  1. 匹配时解构会转移所有权 (枚举带 String/Vec 等堆类型)
  2. ref / & 借用避免转移:
rust 复制代码
let msg = Msg::Write("test".into());
match msg {
    Msg::Write(ref s) => println!("{}", s), // 借用,不拿走所有权
    _ => ()
}
// 等价写法:if let Msg::Write(s) = &msg

五、枚举内存布局(重点,结合栈/堆区分)

1. 无数据单元枚举(C 风格)

底层是判别标签 (discriminant),单字节/单机器字,全部存栈,极小。

rust 复制代码
enum BoolLike { True, False } // 内存仅一个标记

2. 带数据枚举

内存 = 判别标签 + 最大变体占用的内存(联合体 union)

情况 内存位置
变体内部是纯栈值(i32、元组(i32,f32)、定长数组[u8;8] 整个枚举实例放栈
变体包含 String/Vec/Box 等智能指针 枚举本体在栈,字段存指针,真实数据在堆
超大变体、递归枚举 必须用 Box 包裹,否则编译报错(无限尺寸)

3. 递归枚举(必考点)

直接嵌套自身会无限大小,编译失败,必须用 Box 把内部枚举放到堆

rust 复制代码
// 报错:无限大小类型
enum List { Cons(i32, List), Nil }

// 正确:Box 栈存指针,子节点堆分配
enum List {
    Cons(i32, Box<List>),
    Nil
}

六、判别式 discriminant(自定义数字值)

#[repr(u8/u16/u32/i32)] 指定底层存储类型,用于 FFI、与 C 交互:

rust 复制代码
#[repr(u8)]
enum Status {
    Ok = 0,
    Fail = 1,
    Timeout = 2
}
// 转为数字:Status::Ok as u8

不加 repr 时,Rust 自动选最小整数存标签,不保证数值。


七、常用标准库枚举(高频开发)

1. Option - 可选值(有无数据)

rust 复制代码
enum Option<T> { Some(T), None }
// 常用:Some(val) / None
// 方法:unwrap(), expect(), map(), or_else()

2. Result<T,E> - 错误处理

rust 复制代码
enum Result<T,E> { Ok(T), Err(E) }
// 文件、IO、函数返回必用;? 操作符仅作用于 Result

3. Ordering - cmp 比较返回

  • Less / Equal / Greater

八、枚举实现方法 impl

枚举和 struct 一样可以 impl 方法:

rust 复制代码
impl Msg {
    fn is_quit(&self) -> bool {
        matches!(self, Msg::Quit)
    }
}
let m = Msg::Quit;
println!("{}", m.is_quit());

工具宏 matches!(变量,变体) 快速返回 bool。


九、模式匹配进阶语法

1. _ 通配符

匹配剩余所有变体,放 match 最后。

2. 解构结构体变体

rust 复制代码
match ev {
    FileEvent::Read { path, .. } => println!("{}", path),
    _ => ()
}

3. 匹配守卫 if

rust 复制代码
match m {
    Msg::Move(x, y) if x > 0 => println!("右移"),
    _ => ()
}

十、枚举 vs 结构体核心区别

对比项 struct enum
字段关系 同时拥有全部字段 同一时间只有一种变体
语义描述 描述一个事物的全部属性 描述事物多种互斥形态
内存布局 平铺所有字段 标签 + 联合体(只存一种变体的数据)

十一、高频易错点总结

⚠️ 以下易错点需特别注意

  1. 递归枚举不加 Box → 编译报错,无限大小
  2. match 必须穷尽所有变体,漏一个直接报错(安全兜底)
  3. 解构带堆类型的枚举会转移所有权 ,需要借用就取引用 &enum 匹配
  4. 单元枚举可以 as 转数字 ,但无 repr 时数值不固定,FFI 必须加 #[repr]
  5. enum 本身默认栈分配 ;只有变体内部包含 Box/Vec/String 时,对应数据才存在堆
  6. 不存在"枚举整体放堆" ,只有 Box<Enum> 时,栈存指针、枚举本体在堆

十二、速记口诀

rust 复制代码
枚举变体分三种,单元元组结构体;
match 匹配必穷尽,if let 简化单分支;
递归嵌套要 Box,否则尺寸无限大;
标签加联合体存内存,带字符串数据进堆;
Option、Result 两大标准枚举,空值错误全靠它。
相关推荐
晓杰在写后端2 小时前
从0到1实现Balatro游戏后端(9):Blind奖励结算与金币系统实现
后端·游戏开发
Patrick_Wilson2 小时前
幂等到底是什么?从前端视角讲透 SQL、HTTP 与 POST 接口的幂等设计
前端·后端·架构
凌览2 小时前
一人公司别再上 Jenkins,真不值
前端·后端
菜鸟谢2 小时前
Rust 元组与数组内存管理笔记
后端
oil欧哟2 小时前
Codex 最佳实践(超级长文):先搞懂 AI,再用好 AI
前端·人工智能·后端
AskHarries2 小时前
把一个外部系统接成 MCP 工具
后端·程序员
释然小师弟2 小时前
Android开发十年:反思与回顾
android·后端·嵌入式
雪隐2 小时前
个人电脑玩AI-04让5060 Ti给你打工——本地FLUX.2 Klein 的 AI 图片生成
人工智能·后端
掘金者阿豪2 小时前
多台服务器日志怎么统一清理?Ansible、Cron与cpolar自动化方案
后端