Rust如何打印作为参数传入的Fn trait类型函数的名称
解决方案
方案1:使用内置的类型名获取工具(无额外侵入性)
Rust 1.68及以上版本提供了std::any::type_name_of_val方法,可以直接获取任意值的类型名字符串。对于普通函数参数,该方法返回的结果就是函数的完整路径名,完全满足打印调试的需求。
修改你的代码如下:
use std::any::type_name_of_val; use std::fmt::Debug; pub async fn loop_until_hit_rate_limit<'a, T, Fut>( object_arr: &'a [T], settings: &'a Settings, pool: &'a PgPool, f: impl Fn(&'a Settings, &'a PgPool, &'a T) -> Fut + Copy, rate_limit: usize, ) where Fut: Future<Output = anyhow::Result<()>>, // 额外加Debug约束,保证前三个参数可以正常打印 T: Debug, Settings: Debug, PgPool: Debug, { // 执行业务逻辑 println!("args were: {:?}, {:?}, {:?}, {}, {}", object_arr, settings, pool, type_name_of_val(&f), rate_limit); }
限制说明
- 如果传入的是捕获了变量的闭包,返回的类型名会包含编译器生成的闭包标识后缀,不会显示自定义名称,但仍可用于区分不同的闭包实例。
- 泛型函数的返回结果会携带泛型参数的类型信息。
如果你使用的Rust版本低于1.68,无法使用
type_name_of_val,可以把函数参数的闭包trait改为具体泛型参数,再用std::any::type_name获取:pub async fn loop_until_hit_rate_limit<'a, T, Fut, F>( object_arr: &'a [T], settings: &'a Settings, pool: &'a PgPool, f: F, rate_limit: usize, ) where F: Fn(&'a Settings, &'a PgPool, &'a T) -> Fut + Copy, Fut: Future<Output = anyhow::Result<()>>, T: Debug, Settings: Debug, PgPool: Debug, { println!("f name: {}", std::any::type_name::<F>()); }
方案2:手动绑定函数名(最精准可控)
如果你需要完全可控的函数名输出,不需要依赖编译生成的类型名,可以修改函数签名,新增一个函数名字段,调用时用stringify!宏直接传入传入函数的标识符:
修改后的函数签名:
pub async fn loop_until_hit_rate_limit<'a, T, Fut>( object_arr: &'a [T], settings: &'a Settings, pool: &'a PgPool, f: impl Fn(&'a Settings, &'a PgPool, &'a T) -> Fut + Copy, // 新增函数名参数 f_name: &'static str, rate_limit: usize, ) where Fut: Future<Output = anyhow::Result<()>>, T: Debug, Settings: Debug, PgPool: Debug, { // 执行业务逻辑 println!("args were: {:?}, {:?}, {:?}, {}, {}", object_arr, settings, pool, f_name, rate_limit); }
调用示例:
// 假设你要传入的函数名为my_handler loop_until_hit_rate_limit( &obj_arr, &settings, &pool, my_handler, // 用stringify宏直接转标识符为字符串,不需要手动硬编码 stringify!(my_handler), 100 ).await;
该方案的优势是完全精准,不管是普通函数还是自定义闭包,都可以传入你想要显示的名称,不会受编译器生成规则影响。
内容的提问来源于stack exchange,提问作者ilmoi
相关产品推荐
相关产品推荐

