有没有办法用宏捕获函数定义的参数类型?

Is there a way to capture the parameter types of a function definition with a macro?

最终,我希望能够像这样在 proc_macro 中包装一个函数:

native_function! {
    fn sum(x:i32, y:i32) -> i32 {
        x+y
    }
}

我正在寻找我需要放入此函数的内容:

#[proc_macro]
pub fn native_function(item: TokenStream) -> TokenStream {
    ...
}

在上面的函数中,我需要能够捕获函数中定义的参数的类型;在这种情况下 - “i32”

我已经尝试了各种方法来做到这一点,但目前我很难过。我试图避免使用派生宏,因为我不想完成和实例化一个结构。我什至不需要完整的解决方案,但如果有人能指出我需要使用的 function/object/library,那就太好了。

syn 是 proc 宏的规范解析库。

使用起来很简单:

let f = syn::parse_macro_input!(item as syn::ItemFn);

let types: Vec<syn::Type> = f
    .sig
    .inputs
    .into_iter()
    .filter_map(|arg| match arg {
        syn::FnArg::Receiver(_) => None,
        syn::FnArg::Typed(syn::PatType { ty, .. }) => Some(*ty),
    })
    .collect();

顺便说一句,你的宏可以是an attribute macro

如果您想知道该类型是否是某个已知类型,请首先注意您永远无法确定;这是因为宏在没有类型信息的情况下运行,并且像 struct i32; 这样的代码是合法的并且会隐藏原始 i32 类型。

如果您接受了这个限制,您真正想要的是将它与 path type. Path types are represented by the Path variant of syn::Type. It has qself, which is the T in <T as Trait>::AssociatedType and None in a simple path (not fully-qualified, just A::B::C), and path, which is the Trait::AssociatedType or A::B::C. Paths are complex; they can contain generics, for example, but if all you want is to check if this is one-segment type of simple identifier like i32, syn has got you covered: just use Path::is_ident() 进行比较。所以:

let is_i32 = match ty {
    syn::Type::Path(ty) => ty.path.is_ident("i32"),
    _ => false,
}

如果要与更复杂的类型进行比较,则必须遍历并匹配 segment-by-segment。