Menu
CoddyTech

带数据的枚举

本课属于 Coddy Rust 学习旅程的“面向对象编程”单元。第 14 课,共 61 课。

Rust 中的基本枚举可以让你定义一个具有固定变体集合的类型,例如 Direction::North 或 Status::Active。不过,Rust 枚举的功能远不止于此。每个变体都可以携带自己的数据,这让枚举在模拟现实场景时非常灵活。

考虑一个消息系统,其中不同类型的消息携带不同的信息。文本消息有内容,移动命令有坐标,而退出信号什么也不包含。在 Rust 中,你可以用一个 enum 表示所有这些:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(u8, u8, u8),
}

每个变体都有不同的形状。Quit 不包含任何数据:它只是一个信号。

Move 使用类似结构体的语法,并带有命名字段。Write 使用元组语法,包含一个 String。ChangeColor 包含三个表示 RGB 分量的值。

创建这些变体的实例如下:

let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);

这种方法的妙处在于,m1、m2、m3 和 m4 的类型都相同:Message。你可以把它们存储在同一个集合中,传递给同一个函数,或者从一个函数中返回任意一种变体。枚举将不同的数据形状统一为一种类型,同时保留每种变体所需的具体信息。

challenge icon

挑战

简单

让我们构建一个通知系统,使用带数据的枚举来表示不同类型的提醒。每种通知类型都携带不同的信息:有些包含消息,有些包含数字值,还有些只是简单的信号。

你将创建两个文件来整理代码:

  • notification.rs:定义一个公开的 Notification 枚举,其中包含三个变体:
    • Alert:包含一条 String 消息(元组语法)
    • Reminder:包含命名字段:title(String)和 minutes(u32)
    • Dismiss:不包含数据,只是一个信号
  • main.rs:引入通知模块,并为每个变体创建一个实例。然后打印每条通知的信息,以展示这三个变体属于同一种类型,但携带不同的数据。

打印时,使用调试格式({:?})来显示每条通知。你需要为枚举派生 Debug 特征,才能用这种方式打印。

输出应显示全部三条通知,每条占一行:

Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
Dismiss

例如,提醒消息为 "Server down",提醒标题为 "Meeting",分钟数为 30 时,输出如下:

Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
Dismiss

你将收到三个输入:提醒消息、提醒标题和提醒分钟数。

亲手试试

mod notification;

use notification::Notification;

fn main() {
    // 读取输入
    let mut alert_message = String::new();
    std::io::stdin().read_line(&mut alert_message).expect("Failed to read line");
    let alert_message = alert_message.trim().to_string();

    let mut reminder_title = String::new();
    std::io::stdin().read_line(&mut reminder_title).expect("Failed to read line");
    let reminder_title = reminder_title.trim().to_string();

    let mut minutes_input = String::new();
    std::io::stdin().read_line(&mut minutes_input).expect("Failed to read line");
    let reminder_minutes: u32 = minutes_input.trim().parse().expect("Failed to parse minutes");

    // TODO:使用 alert_message 创建 Alert 通知

    // TODO:使用 reminder_title 和 reminder_minutes 创建 Reminder 通知

    // TODO:创建 Dismiss 通知

    // TODO:使用调试格式 {:?} 打印每条通知
    // 每条通知单独打印一行
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Rust 在线编译器