rust upcast and downcast
https://blog.csdn.net/wowotuo/article/details/116489754
所有 trait 的方法是顺序放在一起,并没有区分方法属于哪个 trait,这样也就导致无法进行 upcast,社区内有 RFC 2765 在追踪这个问题,感兴趣的读者可参考,这里就不讨论解决方案了,介绍一种比较通用的解决方案,通过引入一个 AsBase 的 trait 来解决:
trait Base { fn base(&self) { println!("base..."); } } trait AsBase { fn as_base(&self) -> &dyn Base; } // blanket implementation impl<T: Base> AsBase for T { fn as_base(&self) -> &dyn Base { self } } trait Foo: AsBase { fn foo(&self) { println!("foo.."); } } #[derive(Debug)] struct MyStruct; impl Foo for MyStruct {} impl Base for MyStruct {} fn main() { let s = MyStruct; let foo: &dyn Foo = &s; foo.foo(); let base: &dyn Base = foo.as_base(); base.base(); }
向下转型(downcast)
向下转型是指把一个 trait object 再转为之前的具体类型,Rust 提供了 Any 这个 trait 来实现这个功能。
大多数类型都实现了 Any,只有那些包含非 'static 引用的类型没有实现。通过 type_id 就能够在运行时判断类型,下面看一示例:
use std::any::Any; trait Greeting { fn greeting(&self) -> &str; fn as_any(&self) -> &dyn Any; } struct Cat; impl Greeting for Cat { fn greeting(&self) -> &str { "Meow!" } fn as_any(&self) -> &dyn Any { self } } fn main() { let cat = Cat; let g: &dyn Greeting = &cat; println!("greeting {}", g.greeting()); // &Cat 类型 let downcast_cat = g.as_any().downcast_ref::<Cat>().unwrap(); println!("greeting {}", downcast_cat.greeting()); } 上面的代码重点在 downcast_ref,其实现为: pub fn downcast_ref<T: Any>(&self) -> Option<&T> { if self.is::<T>() { unsafe { Some(&*(self as *const dyn Any as *const T)) } } else { None } }