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
    }
}

  

 

posted @ 2022-07-11 16:45  CrossPython  阅读(397)  评论(0编辑  收藏  举报