简介
结构体将始终属于同一对象的字段组合在一起。枚举用于表示一个可能属于多个替代方案之一的值,并且每个替代方案可以携带不同的数据。Rust 的 match 表达式可以显式处理这些替代方案。
你将完成一个消息枚举,从其中一个变体中解构坐标数据,并通过添加新变体扩展这个模型。在消息处理器运行之前,编译器会明确提示为什么必须覆盖所有可能的变体。
定义携带数据的变体
在这一步中,你将为同一个 Message 类型定义三种不同的替代形态。
进入准备好的项目并打开源文件:
cd /home/labex/project/message-processor
nano src/main.rs
枚举声明会在花括号中列出变体。构造变体时,需要使用枚举名称、:: 和变体名称。同一个枚举的不同变体可以携带不同类型的数据。
将步骤 1 的注释替换为:
Text(String),
Move { x: i32, y: i32 },
Stop,
Text(String) 携带一个未命名的值,这种形式在 Rust 中称为元组式变体。Move { x, y } 携带命名字段,因此称为结构体式变体。Stop 不携带额外数据,称为单元变体。刚开始记住「一个未命名的值、命名字段或没有数据」比立即记忆这些正式名称更重要。虽然它们的形态不同,但每个构造出的值都属于同一个 Message 类型。
使用 Ctrl+O 保存,按 Enter 确认,然后使用 Ctrl+X 退出。检查并运行准备好的处理器:
cargo check
cargo run --quiet
输出应为:
Text: Maintenance at 9
Move received
Stop requested
准备好的 match 会为每个变体选择一个分支。每个分支都采用 pattern => behavior 的形式,简短分支之间使用逗号分隔。Text(text) 模式会为携带的字符串命名。Move 分支也会为 x 和 y 命名,然后暂时将它们组合为 (x, y)。这里的括号只会创建一个包含两个值的元组,用作准备好的脚手架;元组不是本实验的学习目标。名称 _coordinates 以下划线开头,表示你有意不使用这个临时值。这样可以确保第一次运行时不会出现警告。下一步中,你将替换这个脚手架,并在可见输出中使用两个坐标。
使用解构后的变体数据
在这一步中,你将修改 Move 的 match 分支,使模式提取出的坐标显示在输出中。
模式可以拆解它所匹配的变体。对于结构体式变体,写出字段名称后,就会创建可供该分支表达式使用的绑定。
打开源文件:
nano src/main.rs
将完整的 Move 分支替换为:
Message::Move { x, y } => println!("Move to ({x}, {y})"),
收到 Move 消息时,该模式会将其中存储的字段绑定到本地名称 x 和 y。打印表达式会直接使用这些名称,不需要单独访问字段,也不需要类型转换。
保存并退出,然后运行:
cargo run --quiet
现在,中间一行应为:
Move to (3, -2)
负数 y 值表明该分支使用了实际变体携带的数据,而不是打印固定坐标。
扩展穷尽式 match
在这一步中,你将添加 Pause 消息,观察编译器的穷尽性检查,然后处理这个新的替代方案。
match 必须覆盖枚举的每个可能值。这条规则意味着,添加一个变体后,所有需要决定如何处理新情况的 match 都会被识别出来。
打开文件,并在 Stop 的正下方添加这个变体:
nano src/main.rs
Pause(u32),
保存并退出,然后检查程序。此时出现失败是预期结果:
cargo check
找到诊断信息中稳定不变的部分:
error[E0004]: non-exhaustive patterns: `Message::Pause(_)` not covered
编译器会指出 match message,因为该枚举现在可能包含 Pause 值,但没有任何分支说明应该如何处理它。
再次打开源文件。在 Stop 分支下方添加这个分支:
Message::Pause(seconds) => println!("Pause for {seconds} seconds"),
然后删除 main 中准备好的 process(Message::Pause(5)); 行开头的 //。该模式会将携带的 u32 值命名为本地变量 seconds。
保存并退出,然后检查并运行:
cargo check
cargo run --quiet
完整输出应为:
Text: Maintenance at 9
Move to (3, -2)
Stop requested
Pause for 5 seconds
检查成功表明 match 再次覆盖了所有可能情况,第四行则表明新的分支成功解构了 Pause 携带的时长。
总结
你定义了单元、元组式和结构体式枚举变体;使用 match 模式解构了携带的数据;并在添加新的替代方案后,利用编译器错误 E0004 以穷尽方式扩展了 match。


