使用syn::ItemFn.to_token_stream时遇编译错误的技术问询
Rust proc_macro_attribute 装饰器类型不匹配问题解决
问题描述
我想写个基础函数装饰器,用来记录函数调用时的输入和输出。手里有一批签名差不多的函数,希望给它们加上#[log_io]装饰器后,自动变成带日志逻辑的版本。
我用#[proc_macro_attribute]来实现,写了下面这段空实现代码(参考syn文档写的,本来以为是有效的):
use proc_macro::TokenStream; use syn; use syn::ItemFn; #[proc_macro_attribute] pub fn log_io(_attr: TokenStream, item: TokenStream) -> TokenStream { let item_fn: ItemFn = syn::parse_macro_input!(item); item_fn.to_token_stream() }
结果编译器报错找不到to_token_stream方法,按提示加了use syn::__private::ToTokens;后,又出现proc_macro::TokenStream和TokenStream2类型不匹配的错误,syn文档里没提这事,求解决。
注:用的依赖版本是syn 1.0.99(开启full、printing、extra-traits特性),proc-macro2 1.0.43。
解决方法
问题根源
syn的ToTokens trait提供的to_token_stream方法返回的是proc_macro2::TokenStream,但proc宏的输入输出要求是proc_macro::TokenStream,这俩是不同类型,不能直接混用。而且syn::__private是内部实现模块,不能直接引用,得导入公开的ToTokens trait。
修正步骤
- 导入正确的Trait:从syn的公开模块导入
ToTokens,别用私有模块的:
use syn::ToTokens;
- 类型转换:
proc_macro2::TokenStream可以通过into()方法转换成proc_macro::TokenStream,因为前者实现了Into<proc_macro::TokenStream>。
修正后的代码:
use proc_macro::TokenStream; use syn; use syn::ItemFn; use syn::ToTokens; #[proc_macro_attribute] pub fn log_io(_attr: TokenStream, item: TokenStream) -> TokenStream { let item_fn: ItemFn = syn::parse_macro_input!(item); item_fn.into_token_stream().into() }
额外说明
into_token_stream()是ToTokens里的方法,和to_token_stream()类似,但返回的是拥有所有权的proc_macro2::TokenStream,更适合后续转换操作。- 要是你后续要添加实际的日志逻辑,可以用
quotecrate生成新的TokenStream。大致思路是:提取函数的参数、返回值信息,用quote生成包裹原函数的代码,在调用前后加入日志打印逻辑,最后把生成的TokenStream转成proc_macro::TokenStream返回。
内容的提问来源于stack exchange,提问作者tarski
相关产品推荐
相关产品推荐

