Rust基础-关于trait之五

基于上一篇Rust基础-关于trait之四-不得不说一下rust fat point

如果Trait之间有继承关系时,vtable 是什么布局呢?

如果看过上一篇,那么这张图应该能够看明白了。

所有的trait这么放,那就没办法 区分fn属于哪个trait了。那么如何upcast呢?

1、upcast

通过用AsBase的trait中转一下的办法。如下代码


trait Human {
    fn human_say(&self) {
        println!("Human...");
    }
}
trait AsHuman {
    fn as_Human(&self) -> &dyn Human;
}
impl<T: Human> AsHuman for T {
    fn as_Human(&self) -> &dyn Human {
        self
    }
}
trait Female: AsHuman {
    fn human_say(&self) {
        println!("Female..");
    }
}
trait Male: AsHuman {
    fn human_say(&self) {
        println!("Male..");
    }
}
#[derive(Debug)]
struct Creature;
impl Female for Creature {}
impl Male for Creature {}
impl Human for Creature {}
fn main() {
    let s: Creature = Creature;
    Human::human_say(&s);
    Female::human_say(&s);
    Male::human_say(&s);

    let Hm: &dyn Human = s.as_Human();
    Hm.human_say();

    let f: &dyn Female = &s;
    f.human_say();
    
    let m:&dyn Male=&s;
    m.human_say();
}

输出

 AsHuman这个trait完成了 Female和Male这两个trait upcast的道路。  polymorphism?yeah

2、downcast

let‘s code:

use std::any::Any;
trait Human {
        fn human_say(&self) {
        println!("Human...");
    }
    fn as_any(&self) -> &dyn Any;
}

trait Female {
    fn human_say(&self) {
    println!("Female...");
}
fn as_any(&self) -> &dyn Any;
}
struct Creature;
impl Human for Creature {
    fn as_any(&self) -> &dyn Any {
        self
    }
}
impl Female for Creature {
    fn as_any(&self) -> &dyn Any {
        self
    }
}
impl Creature{
    fn dance(&self){
        println!("let dance!");
    }
}
fn main() {
    let C = Creature;

    let hm: &dyn Human = &C;
    hm.human_say();


    let downcast_hm = hm.as_any().downcast_ref::<Creature>().unwrap();
    Human::human_say(downcast_hm);
    Female::human_say(downcast_hm);
    downcast_hm.dance();
}

这段代码把hm 这个trait object再次转回Creature这个struct。Rust的Any这个trait提供这个能力。

pub trait Any: 'static {
    fn type_id(&self) -> TypeId;
}
//通过 type_id 就能够在运行时判断类型,不同于反射。

通过Any::type_id返回TypeId,再通过downcast_ref转回Creature这个objct。

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

在类型一致时(if self.is::<T>()),通过 unsafe 代码把 trait object 引用的第一个指针(即 data 指针)转为了指向具体类型的引用。
 

3、最后讲一下trait的compose

let's code:


trait Human {
    fn Human_say(&self) {
        println!("Human...");
    }
}
trait Boy:Human  {
    fn Boy_say(&self) {
        println!("Boy..");
    }
}
trait Wife  {
    fn Wife_say(&self) {
        println!("Wife..");
    }
}
trait Family :Boy+Wife {
    fn Family_say(&self) {
        println!("Family..");
    }
}
struct Creature;
impl Human for Creature {}
impl Boy for Creature {}
impl Wife for Creature {}
impl Family for Creature {}
fn Man(Tom: &dyn Family){
        Tom.Human_say();
        Tom.Boy_say();
        Tom.Wife_say();
        Tom.Family_say();
}

fn main() {
    let s: Creature = Creature;
    Man(&s);
}

以上的例子,把顺序的继承关系改为平行的组合关系,相对于downcast和upcast这样的做法更清楚更易维护。但在不同的情况下各有优劣,还是要具体分析的。

相关文章

Rust基础-关于trait之一_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之二_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之三_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之四-不得不说一下rust fat point_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之六,动态派发和静态派发的区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值