You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调试自定义Rust过程宏并查看其展开输出?

调试Rust自定义过程宏并查看展开输出的正确方法

一、解决「同一crate内无法使用自定义过程宏」的问题

Rust过程宏必须定义在独立的proc-macro crate中,无法在同一个crate内同时定义和直接使用(测试代码也受此限制)。正确的项目结构需要拆分三个模块:

  • 公共trait crate:定义宏依赖的trait,供宏和业务代码共同引用
  • proc-macro crate:实现自定义过程宏
  • 业务/测试crate:调用过程宏

标准项目结构

my_project/
├── Cargo.toml
├── src/
│   └── main.rs
├── hello_macro/          # 公共trait crate
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
└── hello_macro_derive/   # proc-macro crate
    ├── Cargo.toml
    └── src/
        └── lib.rs

各模块代码配置

  1. hello_macro(公共trait crate)
    Cargo.toml:
[package]
name = "hello_macro"
version = "0.1.0"
edition = "2021"

src/lib.rs:

pub trait HelloMacro {
    fn hello_macro() -> String;
}
  1. hello_macro_derive(proc-macro crate)
    Cargo.toml必须声明为proc-macro类型:
[package]
name = "hello_macro_derive"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
syn = { version = "2.0", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"
hello_macro = { path = "../hello_macro" }

src/lib.rs(修正宏代码,引用公共trait):

use syn;
use quote::quote;
use proc_macro;
use hello_macro::HelloMacro;

#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse(input).unwrap();
    impl_hello_macro(&ast)
}

fn impl_hello_macro(ast: &syn::DeriveInput) -> proc_macro::TokenStream {
    let name = &ast.ident;
    let gen = quote! {
        impl HelloMacro for #name {
            fn hello_macro() -> String {
                String::from(stringify!(#name))
            }
        }
    };
    gen.into()
}
  1. 业务/测试crate
    Cargo.toml:
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"

[dependencies]
hello_macro = { path = "./hello_macro" }
hello_macro_derive = { path = "./hello_macro_derive" }

src/main.rs(含测试代码):

use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;

#[derive(HelloMacro)]
struct A;

fn main() {
    println!("{}", A::hello_macro());
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_macro() {
        assert_eq!(A::hello_macro(), "A".to_string());
    }
}

二、使用cargo-expand查看宏展开(推荐)

解决版本兼容问题

cargo-expand必须与当前rustc版本匹配,执行以下命令同步版本:

rustup component add rustfmt --toolchain nightly
cargo +nightly install cargo-expand

执行展开命令

  • 查看主代码宏展开:
    cargo +nightly expand
    
  • 查看测试代码宏展开:
    cargo +nightly expand --test tests
    

三、用rustc直接展开的方法

若不想使用cargo-expand,可在业务crate目录下执行(注意替换平台对应的动态库后缀:Windows为.dll,macOS为.dylib):

rustc +nightly -Zunpretty=expanded src/main.rs --extern hello_macro=target/debug/deps/libhello_macro.rlib --extern hello_macro_derive=target/debug/deps/libhello_macro_derive.so

四、额外调试技巧

  • 打印生成的代码:在宏实现中加入字符串转换打印,执行测试时用cargo test -- --nocapture查看输出:
    let gen = quote! { ... };
    println!("Generated code:\n{}", gen.to_string());
    gen.into()
    
  • 查看语法树结构:对syn的语法树节点调用.dump()方法,打印详细结构:
    println!("AST structure:\n{}", ast.dump());
    

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:05:20