如何获取&dyn Trait背后变量的实际类型?
问题
我尝试打印变量x和y的类型(二者类型均为Foo,且Foo实现了Bar trait)。但将它们传入print_name()函数时,x以&Foo类型传入,y以&dyn Bar类型传入,得到的类型名称不同:
x: &rust_test::Foo y: &dyn rust_test::Bar
如何修改该程序,使得传入&dyn Bar类型变量时能获取到Foo类型?
完整代码:
use std::any::type_name; fn type_of<T: ?Sized>(_: &T) -> String { type_name::<T>().to_string() } struct Foo {} trait Bar {} impl Bar for Foo {} fn print_name(x: &Foo, y: &dyn Bar) { println!("x: {}", type_of(&x)); println!("y: {}", type_of(&y)); } fn main() { let x = Foo {}; let y = Foo {}; print_name(&x, &y); /* x: &rust_test::Foo y: &dyn rust_test::Bar */ }
解决方案
要从&dyn Bar中获取实际类型Foo的名称,需要借助std::any::Any trait——动态分发的trait对象只有实现Any后,才能完成向下转型并获取具体类型信息。
修改步骤
- 让
trait Bar继承Anytrait; - 在
Bar中添加as_any方法,用于将&self转换为&dyn Any; - 在
Foo对Bar的实现中,实现as_any方法; - 在
print_name函数中,通过as_any尝试向下转型为&Foo,再获取其类型名称。
修改后的完整代码:
use std::any::{Any, type_name}; fn type_of<T: ?Sized>(_: &T) -> String { type_name::<T>().to_string() } struct Foo {} trait Bar: Any { fn as_any(&self) -> &dyn Any; } impl Bar for Foo { fn as_any(&self) -> &dyn Any { self } } fn print_name(x: &Foo, y: &dyn Bar) { println!("x: {}", type_of(&x)); // 尝试将dyn Bar转型为Foo,成功则获取类型名 if let Some(foo) = y.as_any().downcast_ref::<Foo>() { println!("y: {}", type_of(&foo)); } else { println!("y: 无法转换为Foo类型"); } } fn main() { let x = Foo {}; let y = Foo {}; print_name(&x, &y); /* 输出结果: x: &rust_test::Foo y: &rust_test::Foo */ }
原理说明
Anytrait内部存储了类型的唯一标识,支持动态类型检查和向下转型;- 通过
as_any方法将trait对象转换为&dyn Any后,使用downcast_ref可以尝试转换为具体的Foo类型; - 转型成功即可获取
Foo的类型名称,也能兼容其他实现了Bar的类型场景。
内容的提问来源于stack exchange,提问作者Rahn
相关产品推荐
相关产品推荐

