变体可以持有数据
#![allow(unused)] fn main() { enum Status { ToDo, InProgress, Done, } }
我们的Status
枚举通常被称为C风格枚举。每个变体都是一个简单的标签,有点像命名常量。你可以在许多编程语言中找到这种枚举,如C、C++、Java、C#、Python等。
不过,Rust的枚举可以更进一步。我们可以在每个变体附加数据。
变体
假设我们想存储当前正在处理票证的人的名字。只有当票证处于进行中状态时,我们才有此信息。对于待办或已完成的票证则不会有此信息。我们可以通过在InProgress
变体上附加一个String
字段来模拟这个模型:
#![allow(unused)] fn main() { enum Status { ToDo, InProgress { assigned_to: String, }, Done, } }
InProgress
现在变成了一个类似结构体的变体。语法实际上反映了我们定义结构体时使用的语法——只是作为变体“内联”在枚举中。
访问变体数据
如果我们尝试访问Status
实例上的assigned_to
,
#![allow(unused)] fn main() { let status: Status = /* */; // This won't compile println!("Assigned to: {}", status.assigned_to); }
编译器会阻止我们:
error[E0609]: no field `assigned_to` on type `Status`
--> src/main.rs:5:40
|
5 | println!("Assigned to: {}", status.assigned_to);
| ^^^^^^^^^^^ unknown field
assigned_to
是特定于变体的,不是所有Status
实例都可用。要访问assigned_to
,我们需要使用模式匹配:
#![allow(unused)] fn main() { match status { Status::InProgress { assigned_to } => { println!("Assigned to: {}", assigned_to); }, Status::ToDo | Status::Done => { println!("Done"); } } }
绑定
在匹配模式Status::InProgress { assigned_to }
中,assigned_to
是一个绑定。我们正在解构Status::InProgress
变体并将assigned_to
字段绑定到一个新变量,也称为assigned_to
。如果我们愿意,我们可以将字段绑定到一个不同的变量名:
#![allow(unused)] fn main() { match status { Status::InProgress { assigned_to: person } => { println!("Assigned to: {}", person); }, Status::ToDo | Status::Done => { println!("Done"); } } }
参考资料
- 本节练习位于
exercises/05_ticket_v2/03_variants_with_data