如何编写自定义派生宏?

Lev*_*Lev 20 rust rust-macros

我正在尝试在 Rust 中编写我自己的派生模式宏,并且它的文档在示例中有些缺乏。

我有一个像这样的结构:

#[derive(MyMacroHere)]
struct Example {
    id: i64,
    value: Option<String>,
}
Run Code Online (Sandbox Code Playgroud)

我希望我的宏生成一个方法 à la

fn set_fields(&mut self, id: i64, value: Option<String>) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

使用TokenStream特征来实现类似目标的基本步骤是什么?

She*_*ter 23

  1. 为您的程序宏创建一个箱子:

    cargo new my_derive --lib
    
    Run Code Online (Sandbox Code Playgroud)
  2. 编辑 Cargo.toml 使其成为程序宏包:

    [lib]
    proc-macro = true
    
    Run Code Online (Sandbox Code Playgroud)
  3. 实现你的程序宏:

    extern crate proc_macro;
    
    use proc_macro::TokenStream;
    
    #[proc_macro_derive(MyMacroHere)]
    pub fn my_macro_here_derive(input: TokenStream) -> TokenStream { 
        // ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 导入程序宏并使用它:

    extern crate my_derive;
    
    use my_derive::MyMacroHere;
    
    #[derive(MyMacroHere)]
    struct Example {
        id: i64,
        value: Option<String>,
    }
    
    Run Code Online (Sandbox Code Playgroud)

难点在于宏的实现。大多数人使用synquote crates 来解析传入的 Rust 代码,然后生成新代码。

例如,syn 的文档以自定义衍生的示例开始。您将解析结构(或枚举或联合),然后处理定义结构(单元、元组、命名字段)的各种方法。您将收集所需的信息(类型,可能是名称),然后生成适当的代码。

也可以看看:

  • 为了使解析更容易,我构建了 [darling](https://crates.io/crates/darling)。它公开了一个类似 `serde` 的 API,你可以在其中为宏需要的参数定义一个结构体,然后将它传递给一个 `syn::DeriveInput`。它处理解析、字段验证、重复字段检查和错误创建。 (3认同)