结构体、枚举与模式匹配
📚 Rust 课程系列
结构体与枚举是 Rust 自定义类型的两大支柱:结构体把数据「组合」在一起,枚举把「互斥的几种可能」表达为一个类型。模式匹配则是对枚举进行分支处理的惯用方式,配合穷尽性检查,让漏处理的分支在编译期就暴露出来。本章把它们放在一起,因为枚举几乎总是和 match 搭配使用。
结构体与枚举
结构体
Rust 提供三种结构体形式:
| 形式 | 语法 | 典型用途 |
|---|---|---|
| 命名结构体 | struct Name { field: T } | 数据记录、业务实体 |
| 元组结构体 | struct Name(T1, T2) | 新类型包装(newtype)、坐标/颜色 |
| 单元结构体 | struct Name; | 实现 trait 但无需持有数据 |
1 | |
🔄 对比:Rust 结构体没有继承,组合通过字段嵌套或 trait 实现。这避免了 C++ 菱形继承和 Java 深层继承链的问题——Rust 用 trait 共享行为,用组合共享数据。
方法与关联函数:使用 impl 块定义。不可变操作用 &self,需要修改用 &mut self;不取 self 参数的是关联函数(类似其他语言的「静态方法」),常作为构造器。
1 | |
💡 提示:一个类型可以写多个
impl块,Rust 会自动合并。关联函数通过Type::method()调用(如String::from、Vec::new)。
打印结构体:最常见的是派生 Debug,然后用 {:?} 或 {:#?} 输出:
1 | |
⚠️ 注意:结构体默认拥有其字段;若要持有引用则需生命周期参数(详见《所有权、借用与生命周期》)。编译器不会让你忘记——尝试存引用而不标注生命周期会直接报错。
枚举
枚举的每个变体可以携带不同类型、不同数量的数据,这让它比「带 tag 的结构体」更灵活:
1 | |
🔄 对比:Rust 枚举 ≈ 函数式语言的 ADT(代数数据类型),远比 C/Java 枚举强大——C 枚举只是整数常量,Java 枚举是单例类,而 Rust 枚举每个变体可以携带完全不同的数据。
标准库核心枚举:Option<T> 和 Result<T, E> 本质上是:
1 | |
Option 取代了「空指针」:凡是可以缺失的值都用 Option<T> 表达,编译器强制你处理 None,从而消除了一整类空指针解引用错误。Result 的深入用法见《错误处理与 Panic 恢复》。
💡 提示:枚举非常适合状态机建模(连接状态、任务状态等),结合
match可保证覆盖所有分支。新增变体后,所有match都会被编译器提醒补全——这是穷尽性检查的核心价值。
枚举也能定义方法:
1 | |
常见模式——带数据的枚举:
1 | |
⚠️ 注意:DTO 与业务实体要区分——接口层返回轻量 DTO,避免将内部可变状态或锁直接暴露给调用者。
模式匹配
match 与 if let
| 构造 | 特点 | 适用场景 |
|---|---|---|
match | 穷尽匹配,必须覆盖所有情况 | 枚举分支、多路分发 |
if let | 只匹配一种模式,其余忽略 | 只关心单一变体 |
while let | 循环匹配,失败则退出 | 逐项解析(如 stack.pop()) |
1 | |
💡 提示:
match是表达式,每个分支返回的值类型必须一致。当你只关心一种情况时,if let更轻量,但放弃了穷尽性检查——未来新增枚举变体时不会提醒你。
⚠️ 注意:当有默认分支时尽量显式写出
_ => {},以便未来扩展时不遗漏处理。在匹配复杂结构时使用解构({ x, y, .. }或(_, _, tail)),并用_/..忽略不必要字段。
解构与绑定
模式匹配可以同时解构结构体、元组、引用,并用 @ 把值绑定到变量同时测试范围:
1 | |
解构也常出现在函数参数和 let 语句中:
1 | |
💡 提示:
@绑定的价值在于「既想对值做范围/模式测试,又想保留整个值供后续使用」,否则测试后只能拿到解构出的子部分。
let-else
Rust 1.65 引入的 let else 适合「匹配失败就提前返回/报错」的场景,比 if let 更适合做早期校验:
1 | |
⚠️ 注意:
let PATTERN = expr else { ... }的else块必须 diverge——即return、break、continue、panic!等不返回的正常路径。匹配成功时绑定直接进入后续作用域,无需额外缩进,这是它比if let+else更优雅的原因。
🔄 对比:
let-else≈ Go 的if err != nil { return err }模式,但类型安全——编译器保证不匹配时你一定会退出,不会意外 fall through。
模式匹配的完整能力(进阶)
Rust 模式匹配远不止 match 和 if let,以下是一个快速参考:
| 模式位置 | 示例 | 说明 |
|---|---|---|
match 分支 | match x { A => .. } | 穷尽匹配 |
if let / while let | if let Some(v) = x | 单一模式 |
let 语句 | let (a, b) = tuple | 解构绑定 |
let-else | let Some(v) = x else { return } | 早期返回 |
| 函数参数 | fn f(&(x, y): &(i32, i32)) | 参数解构 |
for 循环 | for (k, v) in map | 迭代解构 |
| 守卫条件 | Some(x) if x > 0 | 附加条件过滤 |
@ 绑定 | n @ 0..=12 | 测试 + 绑定 |
.. 忽略 | Point { x, .. } | 忽略剩余字段 |
🔬 进阶:Rust 的模式分为不可反驳的(irrefutable,如
let (a, b) = (1, 2)必定成功)和可反驳的(refutable,如if let Some(x) = opt可能失败)。let和函数参数只接受不可反驳模式;match/if let/while let接受可反驳模式。混用会直接编译报错。


