引言
Rust 的宏系统是其最强大的元编程工具,分为两大类:声明宏(macro_rules!)和过程宏(Procedural Macros)。声明宏基于模式匹配,适合简单的代码生成场景;过程宏则直接操作抽象语法树(AST),能实现任意复杂的编译时代码变换。本文聚焦过程宏,系统讲解从基础原理到工程落地的完整链路。
1. 过程宏三大类型
过程宏根据用途分为三种形式:
- 属性宏(Attribute-like):以
#[my_attribute]形式作用于任意 item,可以替换被标注的整个语法节点。典型用例:#[tokio::main]、#[derive(Serialize)]的扩展版。 - 派生宏(Derive macro):以
#[derive(MyTrait)]形式作用于 struct/enum,为类型自动生成 trait 实现。典型用例:#[derive(Debug, Clone, Serialize, Deserialize)]。 - 函数形宏(Function-like):以
my_macro!(...)形式调用,接受任意 token 输入,产生任意输出。典型用例:vec!、println!的扩展版。
2. TokenStream 与语法树操作
过程宏的核心输入和输出都是 proc_macro::TokenStream(或 proc_macro2::TokenStream)。TokenStream 是词法 token 的序列,不会直接暴露 AST 节点,因此通常需要配合解析库使用。
常用解析工具链:
- syn:将 TokenStream 解析为强类型的 AST 节点,支持 struct、enum、函数、表达式等任意 Rust 语法结构的精确解析。
- quote:将 Rust 语法结构 quote 回 TokenStream,提供
quote! 宏和
ToTokenstrait。 - proc-macro2:
proc_macro的包装库,可在非过程宏代码中测试和复用。
3. 派生宏实战:为自定义 Trait 生成实现
假设我们需要为所有结构体自动实现 Describe trait,该 trait 返回描述结构体字段名称和类型的字符串。
定义目标 trait:
trait Describe {
fn describe() -> String;
}
实现派生宏:
#[proc_macro_derive(Describe)]
fn derive_describe(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_describe(

发表评论 取消回复