You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取&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继承Any trait;
  • 在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
    */
}

原理说明

  • Any trait内部存储了类型的唯一标识,支持动态类型检查和向下转型;
  • 通过as_any方法将trait对象转换为&dyn Any后,使用downcast_ref可以尝试转换为具体的Foo类型;
  • 转型成功即可获取Foo的类型名称,也能兼容其他实现了Bar的类型场景。

内容的提问来源于stack exchange,提问作者Rahn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:02:49