rust 属性宏(attribute macro)的用法示例

举报
福州司马懿 发表于 2025/09/25 10:17:01 2025/09/25
【摘要】 在 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)
}

属性宏的工作原理

  1. #[proc_macro_attribute]

    • 标记一个函数为属性宏处理器。
    • 接收两个参数:
      • _attr: TokenStream(属性参数,如 #[my_attr(param)]
      • item: TokenStream(被标记的代码项,如函数、结构体等)
  2. synquote

    • syn 用于解析 Rust 代码为语法树(AST)。
    • quote 用于将 AST 转换回 Rust 代码。
  3. 代码生成

    • 属性宏可以修改、扩展或完全替换被标记的代码。

完整示例:自定义 #[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

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。