本文最后更新于 2025-02-25T11:53:13+08:00
Rust 的宏系统分为两大类: 声明宏 (Declarative Macros)和 过程宏 (Procedural Macros)。
1. 宏的基本概念
1.1 宏的作用
- 代码复用 :通过宏减少重复代码。
- 代码生成 :在编译时生成代码,减少运行时开销。
- 领域特定语言(DSL) :通过宏创建自定义语法。
1.2 宏的分类
- 声明宏 :通过模式匹配生成代码,使用
macro_rules!
定义。
- 过程宏 :更灵活,允许在编译时运行 Rust 代码生成代码,分为三类:
- 自定义派生宏 (Custom Derive Macros):为结构体或枚举自动实现 trait。
- 类属性宏 (Attribute-like Macros):为代码块添加自定义属性。
- 类函数宏 (Function-like Macros):像函数一样调用的宏。
2. 声明宏(Declarative Macros)
2.1 声明宏的定义
使用 macro_rules!
定义声明宏,语法如下:
1 2 3 4 5
| macro_rules! macro_name { (pattern1) => { generated_code1 }; (pattern2) => { generated_code2 }; }
|
pattern
:匹配输入的语法模式。
generated_code
:生成的代码。
2.2 示例:简单的声明宏
1 2 3 4 5 6 7 8 9
| macro_rules! say_hello { () => { println!("Hello, world!"); }; }
fn main() { say_hello!(); }
|
2.3 模式匹配与捕获
声明宏支持多种模式匹配和捕获:
- 捕获变量 :
$var:type
,例如 $x:expr
捕获表达式。
- 重复模式 :
$(...)*
或 $(...)+
,用于匹配重复的输入。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| macro_rules! create_vector { ($($x:expr),*) => { { let mut v = Vec::new(); $(v.push($x);)* v } }; }
fn main() { let v = create_vector!(1, 2, 3); println!("{:?}", v); }
|
3. 过程宏(Procedural Macros)
过程宏更强大,允许在编译时运行 Rust 代码生成代码。过程宏需要单独放在一个 crate 中。
3.1 自定义派生宏(Custom Derive Macros)
派生宏用于为结构体或枚举自动实现 trait。
3.1.1 定义派生宏
使用 #[proc_macro_derive]
定义派生宏。
示例:实现一个简单的 Hello
trait。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(Hello)] pub fn hello_derive(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident;
let gen = quote! { impl Hello for #name { fn hello() { println!("Hello, I am {}", stringify!(#name)); } } };
gen.into() }
|
3.1.2 使用派生宏
1 2 3 4 5 6 7 8
| use hello_macro::Hello;
#[derive(Hello)] struct Person;
fn main() { Person::hello(); }
|
3.2 类属性宏(Attribute-like Macros)
类属性宏允许为代码块添加自定义属性。
3.2.1 定义类属性宏
使用 #[proc_macro_attribute]
定义类属性宏。
示例:定义一个属性宏,打印函数名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, ItemFn};
#[proc_macro_attribute] pub fn log_function(_attr: TokenStream, item: TokenStream) -> TokenStream { let input = parse_macro_input!(item as ItemFn); let fn_name = &input.sig.ident;
let gen = quote! { #input
println!("Function '{}' was called.", stringify!(#fn_name)); };
gen.into() }
|
3.2.2 使用类属性宏
1 2 3 4 5 6 7 8 9 10 11
| use log_macro::log_function;
#[log_function] fn my_function() { println!("Doing something..."); }
fn main() { my_function(); }
|
3.3 类函数宏(Function-like Macros)
类函数宏像函数一样调用,但可以接受任意输入。
3.3.1 定义类函数宏
使用 #[proc_macro]
定义类函数宏。
示例:定义一个类函数宏,生成一个简单的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| use proc_macro::TokenStream; use quote::quote;
#[proc_macro] pub fn make_function(input: TokenStream) -> TokenStream { let gen = quote! { fn generated_function() { println!("This is a generated function!"); } };
gen.into() }
|
3.3.2 使用类函数宏
1 2 3 4 5 6 7 8
| use make_function::make_function;
make_function!();
fn main() { generated_function(); }
|