ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Rustlings enums 章节精讲:用枚举变体与模式匹配表达代数数据类型

Rustlings enums 章节精讲:用枚举变体与模式匹配表达代数数据类型 Rustlings enums 章节精讲用枚举变体与模式匹配表达代数数据类型【免费下载链接】rustlings:crab: Small exercises to get you used to reading and writing Rust code!项目地址: https://gitcode.com/gh_mirrors/ru/rustlingsRust 的枚举enum是一种枚举出所有可能取值的类型定义机制Rustlings 的 enums 章节将其定位为与函数式语言F#、OCaml、Haskell中代数数据类型ADT相当的核心特性并强调其与模式匹配pattern matching配合使用的价值。本篇围绕 exercises/08_enums 下的三道递进式练习enums1、enums2、enums3展开从定义最简单的单元变体到为变体携带数据结构体式、元组式两种形式再到用match对枚举进行解构分发最后结合 Rustlings 工具链的run/hint机制说明如何在本仓库中实际完成并验证这一章节。为什么 Rust 的枚举与其他语言不同章节 README 开篇即指出枚举是许多语言都具备的特性但各语言的枚举能力参差不齐Rust 的枚举最接近函数式语言的代数数据类型。其关键差异在于Rust 的每个变体variant可以携带不同的数据并且编译器强制对枚举做穷尽处理。对照 exercises/README.md 中的练习到书章节映射表enums 对应 The Rust Book 的 §6枚举与模式匹配与 §19.3模式语法这也解释了本章练习的组织方式——先认识变体形态再落到模式匹配上。Rustlings 仓库为每个练习同时维护了两份文件待完成的练习文件exercises/下含TODO占位与参考解答solutions/下。例如 enums1 的练习与解答分别是 exercises/08_enums/enums1.rs 和 solutions/08_enums/enums1.rs这种题目 标准答案的结构本身就是理解每个知识点的最佳路径。enums1单元变体与#[derive(Debug)]练习文件 enums1.rs 给出了骨架#[derive(Debug)] enum Message { // TODO: Define a few types of messages as used below. } fn main() { println!({:?}, Message::Resize); println!({:?}, Message::Move); println!({:?}, Message::Echo); println!({:?}, Message::ChangeColor); println!({:?}, Message::Quit); }main函数用{:?}调试格式打印了五个变体因此需要补全的正是这五个不携带数据的单元变体。标准解答 为#[derive(Debug)] enum Message { Resize, Move, Echo, ChangeColor, Quit, }这里有两个值得注意的实现细节#[derive(Debug)]的必要性{:?}格式化要求类型实现Debugtrait。单元变体枚举无法手动感知内容derive宏会在编译期为Message自动生成Debug实现直接打印变体名如Resize。若移除deriveprintln!({:?}, Message::Resize)会因Message未实现Debug而编译失败。单元变体unit-like variant的语义这种形态等价于 C 的枚举常量仅表示某件事发生了不携带任何状态。这也是为什么 info.toml 中该练习的 hint 只有一句 No hints this time ;)见 rustlings-macros/info.toml 第 434 行附近——它被设计成本章的热身。用 Rustlings 运行与查看提示的命令命令定义见 src/cli.rs 中的Command枚举rustlings run enums1 # 编译并运行该练习通过后标记为 done rustlings hint enums1 # 输出该练习的提示enums2让变体携带数据——三种变体形态第二个练习 enums2.rs 要求变体携带真实数据。练习给出的构造表达式已经暗示了每个变体应有的形态#[derive(Debug)] struct Point { x: u64, y: u64, } #[derive(Debug)] enum Message { // TODO: Define the different variants used below. } impl Message { fn call(self) { println!({self:?}); } } fn main() { let messages [ Message::Resize { width: 10, height: 30 }, Message::Move(Point { x: 10, y: 15 }), Message::Echo(String::from(hello world)), Message::ChangeColor(200, 255, 255), Message::Quit, ]; for message in messages { message.call(); } }info.toml 中为 enums2 配置的官方 hint 明确给出了三种变体形态的命名与示例Enum variants can be defined using three different forms: struct-, tuple- and unit-like.enum EnumUsingAllVariantForms { StructLike { named_field: bool }, TupleLike(bool), UnitLike, }对照main中的构造方式可以逐个确定每个变体的形态与字段类型变体构造方式形态应定义的类型ResizeResize { width: 10, height: 30 }结构体式struct-likeResize { width: u64, height: u64 }MoveMove(Point { x: 10, y: 15 })元组式tuple-like携带一个struct Point值Move(Point)EchoEcho(String::from(hello world))元组式携带StringEcho(String)ChangeColorChangeColor(200, 255, 255)元组式携带三个无符号字节ChangeColor(u8, u8, u8)QuitQuit单元式unit-likeQuitsolutions/08_enums/enums2.rs 中的完整定义为#[derive(Debug)] enum Message { Resize { width: u64, height: u64 }, Move(Point), Echo(String), ChangeColor(u8, u8, u8), Quit, }几个类型的取值细节值得留意width/height取u64与Point的x、y字段类型一致见练习文件中已给出的struct Point定义ChangeColor(u8, u8, u8)三个分量对应 RGB 三原色u8的取值范围 0~255 正好覆盖标准颜色通道的量程——这正是元组式变体适合表达一组同质数据的场景元组式变体的分量是匿名的只能按位置取值结构体式变体是具名字段可按名字取值。二者的取舍通常取决于字段是否有自解释的语义宽高用名字更清晰RGB 三通道用位置足矣。此外练习还展示了枚举上的方法实现impl Message { fn call(self) }接收self以引用方式访问枚举值并打印。main中通过for message in messages遍历切片借用逐个调用message.call()——这说明枚举值与结构体一样是普通类型可以放进数组、取引用、实现方法只是类型的取值空间被显式枚举了出来。运行验证时注意该练习在 info.toml 中标记为test false即rustlings run enums2只要求编译并正常执行、输出五个变体的Debug表示没有断言测试。enums3用match解构枚举驱动状态机第三个练习 enums3.rs 把枚举、方法与单元测试串起来Message的定义已给出同 enums2 解答核心任务是实现State::process把每种消息分发给对应的处理方法impl State { fn resize(mut self, width: u64, height: u64) { ... } fn move_position(mut self, point: Point) { ... } fn echo(mut self, s: String) { ... } fn change_color(mut self, red: u8, green: u8, blue: u8) { ... } fn quit(mut self) { ... } fn process(mut self, message: Message) { // TODO: Create a match expression to process the different message // variants using the methods defined above. } }官方 hintinfo.toml分两步给出指引先定义枚举使其通过编译再在process()中创建match表达式并特别提醒需要在 match 表达式中解构deconstruct某些消息变体以取出其值。solutions/08_enums/enums3.rs 中process的实现即本章模式匹配主题的落点fn process(mut self, message: Message) { match message { Message::Resize { width, height } self.resize(width, height), Message::Move(point) self.move_position(point), Message::Echo(string) self.echo(string), Message::ChangeColor(red, green, blue) self.change_color(red, green, blue), Message::Quit self.quit(), } }这段代码体现了模式匹配解构变体的三种写法结构体式变体Message::Resize { width, height }按字段名解构width、height直接成为匹配臂里的绑定变量元组式变体Message::ChangeColor(red, green, blue)按位置解构三个u8分量Message::Move(point)则是整体绑定Point值单元式变体Message::Quit无需绑定直接映射到self.quit()。更关键的是 Rust 的穷尽性检查match必须覆盖Message的全部五个变体遗漏任何一个例如忘了Quit都会产生编译错误而非静默忽略。从 solutions/08_enums/enums3.rs 与 exercises/08_enums/enums3.rs 的对照可见两者除process的实现和一处注释外完全一致——这正是 rustlings 的练习机制练习文件删除关键代码段解答文件补全后作为验收基准。练习文件末尾的#[cfg(test)]测试模块则是穷尽性的直接验证器#[test] fn test_match_message_call() { let mut state State { width: 0, height: 0, position: Point { x: 0, y: 0 }, message: String::from(hello world), color: (0, 0, 0), quit: false, }; state.process(Message::Resize { width: 10, height: 30 }); state.process(Message::Move(Point { x: 10, y: 15 })); state.process(Message::Echo(String::from(Hello world!))); state.process(Message::ChangeColor(255, 0, 255)); state.process(Message::Quit); assert_eq!(state.width, 10); assert_eq!(state.height, 30); assert_eq!(state.position.x, 10); assert_eq!(state.position.y, 15); assert_eq!(state.message, Hello world!); assert_eq!(state.color, (255, 0, 255)); assert!(state.quit); }测试依次向State投递五种消息再逐一断言各字段是否按预期更新——width/height变为 10/30、位置变为 (10, 15)、消息字符串被替换、颜色变为 (255, 0, 255)、quit置为true。由于该练习在 info.toml 中没有test false标记rustlings run enums3会以cargo test方式执行此测试全部断言通过才判定完成——这与 enums1/enums2 的编译 运行验收标准不同。从源码结构看这套练习/解答双轨机制由 dev/Cargo.toml 中的 target 清单驱动每个练习注册为一对 target如enums1与enums1_sol分别指向../exercises/08_enums/enums1.rs与../solutions/08_enums/enums1.rs配合 rustlings-macros/info.toml 中的name、dir、test、hint元数据由rustlings的run/hint/check-all子命令定义于 src/cli.rs统一调度。想批量核验本章进度可以执行rustlings check-all查看各练习的 done/pending 状态。小结本章练习的知识递进练习核心知识点验收方式enums1单元变体、#[derive(Debug)]与{:?}打印编译并运行test falseenums2结构体式 / 元组式 / 单元式三种变体形态、携带数据的变体、枚举上的impl方法编译并运行test falseenums3match穷尽匹配与变体解构、以枚举消息驱动状态更新编译 cargo test断言这一章的完整学习闭环是先理解Rust 枚举 代数数据类型这一定位再依次掌握变体能携带什么数据三种形态与如何把数据取出来模式匹配解构最后依靠编译器的穷尽性检查与单元测试test_match_message_call双重保证分发逻辑没有遗漏。完成 exercises/08_enums 全部三个练习后读者即可具备编写消息驱动状态机这类典型 Rust 模式的基础这也是后续 20_threads 等章节中多线程消息传递的常见写法。【免费下载链接】rustlings:crab: Small exercises to get you used to reading and writing Rust code!项目地址: https://gitcode.com/gh_mirrors/ru/rustlings创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表