enum 中文一般叫:
枚举类型
但注意⚠️:
Rust 的 enum ≠ C / Java 里的 enum
更准确的中文其实是:
代数数据类型(和类型)的一种:枚举(带数据)
只是平时大家偷懒还叫“枚举”。
struct 中文一般叫:
结构体
❌不是「构造」
👉什么时候用struct,什么时候用enum,为什么。
struct = “同时拥有的东西”
enum = “只能选一个的可能性”
1️⃣ struct:并列存在
structPerson {
name: String,
age: u8,
}
含义是:
一个Person同时有name和age
你不能说:
👉它们是“同时成立”的
2️⃣ enum:互斥选择
enumLight {
Red,
Yellow,
Green,
}
含义是:
一个Light此刻只能是其中一个
它不可能:
👉这就是“状态”
struct vs enum 的核心分水岭
这些东西,是“一起存在”,还是“只能选一个”?
一起存在 →struct
只能选一个 →enum
①Envelope为什么是 struct?
pubstructEnvelope {
pub from: Peer,
pub to: Peer,
pub host_id: Option<String>,
pub payload: Payload,
}
问一句话:
一条消息,会不会同时有 from、to、payload?
答案是:必须同时有
所以它是struct
②Peer为什么是 enum?
pubenumPeer {
UI,
Agent,
}
问一句话:
一个发送方,能不能既是 UI 又是 Agent?
不能。
👉只能选一个身份
所以是enum
③Payload为什么是 enum?
pubenumPayload {
UiCommand(UiCommand),
UiEvent(UiEvent),
AgentCommand(AgentCommand),
AgentEvent(AgentEvent),
}
问一句话:
一条消息,能不能同时是 UiCommand 和 AgentEvent?
不能。
👉一次消息只有一种“内容类型”
所以是enum
④UiCommand为什么又是 enum?
pubenumUiCommand {
StartScreen { quality: u8 },
StopScreen,
RunCmd { cmd: String },
QuerySystemInfo,
}
问一句话:
一次 UI 命令,会不会又是 StartScreen 又是 RunCmd?
不会。
👉命令是“动作的选择”
所以是enum
| 你想表达的意思 | 用什么 |
|---|
| 一个东西有多个字段 | struct |
| 多种状态之一 | enum |
| 多种命令之一 | enum |
| 一个实体的属性 | struct |
| if / else / switch 的数据版 | enum |
enum = 状态 / 行为集合
struct = 实体 / 容器
读代码理解学习
fn route(env: Envelope) {
log::debug!("{} -> {}", env.from, env.to);
match env.payload {
Payload::UiCommand(cmd)=> handle_ui_cmd(cmd),
Payload::AgentEvent(ev)=> handle_agent_event(ev),
_ => {}
}
}
Option 的优势是:
match env.host_id {
Some(id) => send_to_agent(id),
None => broadcast(),
}
pub enum UiCommand {
StartScreen { quality: u8 },
StopScreen,
RunCmd { cmd: String },
QuerySystemInfo,
}
你心里大概率在想:
enum 不是只能是 A / B / C 吗?
为什么还能带 { quality: u8 }?
这是 Rust enum 的核心能力。
enum = 多个「构造器(variant)」的集合
每个构造器,都可以带自己的数据
换句话说:
enum 的每一项,本身就像一个“迷你 struct / tuple”
为什么这里用{}而不是()?
Rust enum 的变体有三种形态,这是关键知识点。
1️⃣ 类 struct 变体(你这个)
StartScreen { quality: u8 }
RunCmd { cmd: String }
特点:
使用时:
UiCommand::StartScreen { quality: 80 }
UiCommand::RunCmd { cmd:
"ls -la".to_string() }
👉推荐:参数有“意义”时用这个
2️⃣ 元组变体(tuple-like)
使用:
UiCommand::RunCmd("ls".to_string())
缺点:
👉参数很少、很明确时才用
3️⃣ 单元变体(unit-like)
StopScreen
QuerySystemInfo
就是:
pubenumUiCommand {
StartScreen { quality: u8 },
// 带字段
StopScreen,
// 无数据
RunCmd { cmd: String },
// 带字段
QuerySystemInfo,
// 无数据
}
UiCommand 不是一个“装参数的盒子”,
而是一组不同命令的“构造方式”:
StartScreen → 需要质量
RunCmd → 需要命令字符串
StopScreen → 什么都不用
QuerySystemInfo → 什么都不用
Rust 的 enum 不是“值列表”,而是“多种构造形态的集合”
{}→ 有名字的字段(像 struct)
()→ 没名字的参数(像 tuple)
什么都没有 → 纯状态
例子:自动售货机的操作
enumAction {
InsertCoin(u32), // 投币(多少钱)
SelectItem { id: u8 },
// 选商品(编号)
Cancel, // 取消
}
先别急着看语法,先看语义:
👉一次只能发生一个动作
二、怎么“创建 / 调用” enum
1️⃣ 创建 enum 的值(重点)
leta1 = Action::InsertCoin(10);
leta2 = Action::SelectItem { id: 3 };
leta3 = Action::Cancel;
记住一句话就行:
enum::变体名(参数)
或
enum::变体名 { 字段: 值 }
三、enum 创建出来之后,怎么“用”?——match
enum 几乎一定搭配match使用。
fnhandle(action: Action) {
match action {
Action::InsertCoin(amount) => {
println!("投了 {} 元", amount);
}
Action::SelectItem { id } => {
println!("选择了 {} 号商品", id);
}
Action::Cancel => {
println!("已取消");
}
}
}
调用它:
handle(a1);
handle(a2);
handle(a3);
①InsertCoin(u32)里的amount从哪来的?
Action::InsertCoin(amount) => { ... }
这是解构(pattern matching):
创建时:InsertCoin(10)
使用时:InsertCoin(amount)
👉amount就是你当初塞进去的10
②{ id }是什么意思?
Action::SelectItem { id } => { ... }
等价于:
Action::SelectItem { id: id }=>{ ... }
意思是:
从{ id: 3 }里把id拿出来
绑定到同名变量id
enum 帮你做了两件事:
保证动作互斥(不会又投币又取消)
强制你处理所有情况
再来一个更简单的例子
表示“请求结果”
enumResultStatus {
Ok(String),
Error { code: i32 },
}
创建:
let r1 = ResultStatus::Ok
("成功".to_string());
letr2 = ResultStatus::Error
{ code: 404 };
使用:
match r1 {
ResultStatus::Ok(msg) =
> println!("{}", msg),
ResultStatus::Error { code }
=> println!("错误码 {}", code),
}
三条“硬规则”
✅ 1. enum 的每一项,是一种“形态”
不是字段赋值,是构造一种形态的值
✅ 2.{}vs()
{}:参数有名字(推荐)
():参数没名字
无参数:纯状态
✅ 3. enum 一定配match
不用 match 的 enum,基本没发挥价值