有没有办法用宏捕获函数定义的参数类型?
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。
最终,我希望能够像这样在 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。