宏的种类
Rust 的宏系统是其强大功能之一,允许你在编译时生成代码。Rust 有两种主要类型的宏:
声明式宏(Declarative Macros) - 使用 macro_rules!
语法过程宏(Procedural Macros) - 更强大也更复杂,分为三种:自定义派生(#[derive]
宏) 属性式宏 函数式宏 声明式宏
使用 macro_rules!
定义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
macro_rules ! my_vec {
// 空向量
() => {
Vec ::new ()
};
// 带初始值的向量
( $($x :expr ), + $(, ) ? ) => {
{
let mut temp_vec = Vec ::new ();
$(
temp_vec . push ( $x );
) +
temp_vec
}
};
}
fn main () {
let v1 : Vec < i32 > = my_vec! ();
let v2 = my_vec! ( 1 , 2 , 3 );
println! ( " {:?} , {:?} " , v1 , v2 ); // [], [1, 2, 3]
}
模式匹配中的元变量:
$x:expr
- 匹配表达式$x:ty
- 匹配类型$x:ident
- 匹配标识符(变量名、函数名等)$x:item
- 匹配项(函数、结构体等)$x:block
- 匹配代码块See 指示符
过程宏
自定义派生宏
自定义派生宏可以使用 derive
属性派生。
定义 (放到一个 lib crate):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use proc_macro ::TokenStream ;
use quote ::quote ;
use syn ::{ parse_macro_input , DeriveInput };
// 定义 trait 让用户实现
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive ( input : TokenStream ) -> TokenStream {
// 解析输入为 DeriveInput 语法树
let input = parse_macro_input! ( input as DeriveInput );
let name = input . ident ;
// 使用 quote! 宏生成代码
let expanded = quote! {
// 为类型实现 HelloMacro trait
impl HelloMacro for #name {
fn hello_macro () {
println! ( "Hello, Macro! My name is {} !" , stringify! ( #name ));
}
}
};
// 将生成的代码转换回 TokenStream
TokenStream ::from ( expanded )
}
使用:
1
2
3
4
5
6
7
8
use hello_macro ::HelloMacro ;
#[derive(HelloMacro)]
struct Pancakes ;
fn main () {
Pancakes ::hello_macro (); // 输出: Hello, Macro! My name is Pancakes!
}
属性式宏
定义 (放到一个 lib crate):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use proc_macro ::TokenStream ;
use quote ::quote ;
use syn ::{ parse_macro_input , AttributeArgs , ItemFn , NestedMeta , Lit };
#[proc_macro_attribute]
pub fn route ( attr : TokenStream , item : TokenStream ) -> TokenStream {
// 解析属性参数
let args = parse_macro_input! ( attr as AttributeArgs );
// 解析被修饰的函数
let input = parse_macro_input! ( item as ItemFn );
// 提取HTTP方法和路径
let http_method = match & args [ 0 ] {
NestedMeta ::Meta ( meta ) => meta . path (). segments [ 0 ]. ident . to_string (),
_ => panic! ( "Expected HTTP method" ),
};
let path = match & args [ 1 ] {
NestedMeta ::Lit ( Lit ::Str ( lit )) => lit . value (),
_ => panic! ( "Expected path string" ),
};
let fn_name = & input . sig . ident ;
let fn_block = & input . block ;
// 生成代码
let expanded = quote! {
fn #fn_name () {
println! ( "注册路由: {} {} , 处理函数: {} " , #http_method , #path , stringify! ( #fn_name ));
#fn_block
}
};
TokenStream ::from ( expanded )
}
使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use my_attribute_macro ::route ;
#[route(GET, "/" )]
fn index () {
println! ( "处理首页请求" );
}
#[route(POST, "/users" )]
fn create_user () {
println! ( "创建新用户" );
}
fn main () {
index ();
create_user ();
}
输出结果:
1
2
3
4
注册路由: GET /, 处理函数: index
处理首页请求
注册路由: POST /users, 处理函数: create_user
创建新用户
函数式宏
定义 (放到一个 lib crate):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use proc_macro ::TokenStream ;
use quote ::quote ;
use syn ::parse_macro_input ;
#[proc_macro]
pub fn sql ( input : TokenStream ) -> TokenStream {
// 解析输入
let input = parse_macro_input! ( input as syn ::Expr );
// 生成代码
let expanded = quote! {
{
println! ( "准备执行SQL: {} " , stringify! ( #input ));
// 这里可以添加实际的SQL执行逻辑
#input . to_string ()
}
};
TokenStream ::from ( expanded )
}
#[proc_macro]
pub fn vec_string ( input : TokenStream ) -> TokenStream {
let input = parse_macro_input! ( input as syn ::ExprArray );
let elements = input . elems . iter (). map ( | e | {
quote! { #e . to_string () }
});
let expanded = quote! {
vec! [ #( #elements ), * ]
};
TokenStream ::from ( expanded )
}
使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use my_function_macro ::{ sql , vec_string };
fn main () {
// 使用sql!宏
let query = sql! ( SELECT * FROM users WHERE id = 1 );
println! ( "生成的查询: {} " , query );
// 使用vec_string!宏
let strings = vec_string! [ "hello" , 42 , true , 3.14 ];
println! ( "字符串向量: {:?} " , strings );
// 更复杂的SQL示例
let user_id = 10 ;
let query2 = sql! {
SELECT name , email FROM users
WHERE id = #user_id AND active = true
};
println! ( "带参数的查询: {} " , query2 );
}
输出结果:
1
2
3
4
5
准备执行SQL: SELECT * FROM users WHERE id = 1
生成的查询: SELECT * FROM users WHERE id = 1
字符串向量: ["hello", "42", "true", "3.14"]
准备执行SQL: SELECT name, email FROM users WHERE id = # user_id AND active = true
带参数的查询: SELECT name, email FROM users WHERE id = 10 AND active = true