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
}
}
浙公网安备 33010602011771号