rust 属性宏(attribute macro)的用法示例
【摘要】 在 Rust 中,属性宏(Attribute Macro) 是一种过程宏(Procedural Macro),它允许你通过 #[attribute_name] 语法对代码项(如函数、结构体、模块等)进行标记,并在编译时生成或修改代码。属性宏通常用于框架设计、代码生成或自定义派生逻辑。 属性宏的基本用法 1. 定义属性宏属性宏需要定义在一个独立的 crate 中,并且需要启用 proc_mac...
在 Rust 中,属性宏(Attribute Macro) 是一种过程宏(Procedural Macro),它允许你通过 #[attribute_name]
语法对代码项(如函数、结构体、模块等)进行标记,并在编译时生成或修改代码。属性宏通常用于框架设计、代码生成或自定义派生逻辑。
属性宏的基本用法
1. 定义属性宏
属性宏需要定义在一个独立的 crate 中,并且需要启用 proc_macro
特性。
示例:定义一个简单的属性宏
// my_macro/src/lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_attribute]
pub fn hello_macro(_attr: TokenStream, item: TokenStream) -> TokenStream {
// 解析输入的代码项(如函数、结构体等)
let input = syn::parse_macro_input!(item as syn::ItemFn);
// 获取函数名
let fn_name = &input.sig.ident;
// 生成新的代码
let expanded = quote! {
#input
// 在原函数前后添加额外逻辑
fn main() {
println!("Before calling {}...", stringify!(#fn_name));
#fn_name();
println!("After calling {}!", stringify!(#fn_name));
}
};
TokenStream::from(expanded)
}
2. 使用属性宏
// src/main.rs
use my_macro::hello_macro;
#[hello_macro]
fn say_hello() {
println!("Hello from say_hello!");
}
fn main() {
say_hello(); // 调用宏生成的代码
}
输出
Before calling say_hello...
Hello from say_hello!
After calling say_hello!
属性宏的常见用途
1. 框架中的路由定义(如 #[get("/")]
)
#[get("/users")]
fn get_users() -> Json<Vec<User>> {
Json(vec![User { id: 1, name: "Alice".into() }])
}
2. 测试框架(如 #[test]
)
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
3. 序列化/反序列化(如 #[derive(Serialize)]
)
#[derive(Serialize, Deserialize)]
struct User {
id: u32,
name: String,
}
4. Tauri 命令(如 #[tauri::command]
)
#[tauri::command]
fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
属性宏的工作原理
-
#[proc_macro_attribute]
- 标记一个函数为属性宏处理器。
- 接收两个参数:
_attr: TokenStream
(属性参数,如#[my_attr(param)]
)item: TokenStream
(被标记的代码项,如函数、结构体等)
-
syn
和quote
syn
用于解析 Rust 代码为语法树(AST)。quote
用于将 AST 转换回 Rust 代码。
-
代码生成
- 属性宏可以修改、扩展或完全替换被标记的代码。
完整示例:自定义 #[route]
宏
1. 定义宏
// web_macro/src/lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
let path = attr.to_string(); // 例如 `"/home"`
let input = syn::parse_macro_input!(item as syn::ItemFn);
let fn_name = &input.sig.ident;
let expanded = quote! {
#input
fn register_routes() {
println!("Registered route: {} -> {}", #path, stringify!(#fn_name));
}
};
TokenStream::from(expanded)
}
2. 使用宏
// src/main.rs
use web_macro::route;
#[route("/home")]
fn home_page() {
println!("Welcome to the home page!");
}
fn main() {
register_routes(); // 由宏生成
home_page();
}
输出
Registered route: /home -> home_page
Welcome to the home page!
总结
特性 | 说明 |
---|---|
定义方式 | #[proc_macro_attribute] |
输入 | 属性参数 + 被标记的代码项 |
输出 | 修改后的 Rust 代码 |
常用库 | syn (解析代码)、quote (生成代码) |
典型用途 | Web 路由、测试、序列化、框架扩展 |
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)