派生宏
实现PartialEq
对于Ticket
来说有点繁琐,对吧?你不得不手动比较结构体中的每一个字段。
解构语法
而且,这种实现方式很脆弱:如果结构体的定义发生变化(比如添加了一个新字段),你还得记得更新PartialEq
的实现。
为了降低风险,你可以使用解构来将结构体分解为各个字段:
#![allow(unused)] fn main() { impl PartialEq for Ticket { fn eq(&self, other: &Self) -> bool { let Ticket { title, description, status, } = self; // [...] } } }
如果Ticket
的定义发生了变化,编译器将会报错,提示你的解构不再全面。你也可以重命名结构体字段,以避免变量遮蔽:
#![allow(unused)] fn main() { impl PartialEq for Ticket { fn eq(&self, other: &Self) -> bool { let Ticket { title, description, status, } = self; let Ticket { title: other_title, description: other_description, status: other_status, } = other; // [...] } } }
解构是一个有用的编程模式,但还有一种更便捷的方式:派生宏(derive macros)。
宏
在之前的练习中,你已经遇到过一些宏:
- 测试用例中的
assert_eq!
和assert!
- 向控制台打印的
println!
Rust的宏是代码生成器。它们根据你提供的输入生成新的Rust代码,这段生成的代码随后会与程序的其他部分一起被编译。有些宏是内置在Rust标准库中的,但你也可以编写自己的宏。虽然本课程不涉及创建宏,但你可以在“进一步阅读”部分找到一些有用的信息。
检视宏
一些集成开发环境(IDE)允许你展开宏以检查生成的代码。如果IDE不支持此功能,你可以使用cargo-expand
工具。
派生宏
派生宏是Rust宏的一种特殊形式。它作为属性放在结构体定义的顶部。
#![allow(unused)] fn main() { #[derive(PartialEq)] struct Ticket { title: String, description: String, status: String, } }
派生宏用于自动为自定义类型实现一些常见(且显而易见)的特质。在上面的例子中,PartialEq
特质自动为Ticket
实现。如果你展开这个宏,会看到生成的代码在功能上等同于你手动编写的代码,尽管读起来可能稍显复杂:
#![allow(unused)] fn main() { #[automatically_derived] impl ::core::cmp::PartialEq for Ticket { #[inline] fn eq(&self, other: &Ticket) -> bool { self.title == other.title && self.description == other.description && self.status == other.status } } }
编译器会在可能的情况下提示你使用派生特质。
参考资料
- 本节的练习位于
exercises/04_traits/04_derive
目录下。