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

在Rust的proc_macro_attribute实现中过滤嵌套的#[fix]属性

过滤proc宏中函数参数的指定属性

直接操作TokenStream的TokenTree来过滤属性容易出错,毕竟Rust语法结构嵌套复杂。更简洁可靠的方式是用syn库解析成抽象语法树(AST),修改后再转回TokenStream,这和标准库#[derive(Default)]处理#[default]属性的逻辑一致。

实现步骤

  1. 添加依赖
    在Cargo.toml中加入syn和quote(proc宏开发的标准工具链):
[dependencies]
syn = { version = "2.0", features = ["full", "parsing"] }
quote = "1.0"
proc-macro2 = "1.0"
  1. 解析并修改语法树
    用syn将输入解析为模块结构,遍历其中的函数,过滤掉参数上的#[fix]属性:
use proc_macro::TokenStream;
use syn::{parse_macro_input, ItemMod, ItemFn, FnArg};
use quote::quote;

#[proc_macro_attribute]
pub fn custom(_attr: TokenStream, input: TokenStream) -> TokenStream {
    // 解析输入为模块项
    let mut module = parse_macro_input!(input as ItemMod);
    
    // 遍历模块内的所有子项
    if let Some((_, items)) = &mut module.content {
        for item in items {
            // 匹配并处理函数项
            if let syn::Item::Fn(func) = item {
                filter_fix_attrs(func);
            }
        }
    }
    
    // 将修改后的语法树转回TokenStream
    quote!(#module).into()
}

// 过滤函数参数上的#[fix]属性
fn filter_fix_attrs(func: &mut ItemFn) {
    for arg in &mut func.sig.inputs {
        // 匹配带属性的普通参数(跳过self相关参数)
        if let FnArg::Typed(pat_type) = arg {
            // 保留所有非#[fix]的属性
            pat_type.attrs.retain(|attr| !attr.path().is_ident("fix"));
        }
    }
}
  1. 测试效果
    使用示例中的代码:
#[custom]
mod MyModule {
  pub fn my_func(
     #[fix] arg1: i32,
     arg2: String // 不受处理影响
  ) {
      // 函数逻辑
  }
}

宏展开后会自动移除#[fix]属性,最终代码为:

mod MyModule {
  pub fn my_func(
     arg1: i32,
     arg2: String
  ) {
      // 函数逻辑
  }
}

关键说明

  • syn的parse_macro_input!宏能安全解析TokenStream为指定语法树类型,若输入语法错误会给出友好的编译提示。
  • 用retain方法过滤属性是最简洁的方式,直接保留非目标属性。
  • 该逻辑可轻松扩展到其他场景(如独立函数、impl块内的方法),只需调整遍历的语法树节点类型即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:07:11