Rust : Trait Object safe 问题

trait就是一种功能,比如,有一个自定义的mytrait trait, 你可以在mytrait里说要实现任何功能(函数);同时你也可以为所需要的对象进行实现(即impl mytrait for any)(注:Copy trait特殊除外)。-------这是你的权利
但是,你不一定可以说,让实现mytrait功能形成特定对象(&mytrait)。-------你要承担一些义务
即对象安全所尽的义务。
从某个角度上讲,trait的可以分安全对象的trait,和非安全对象的trait,只有安全对象的trait,才有资格带上&。比如,你看不到&Clone或Box < Clone>

此前,碰到这种情况,代码如下:

#[derive(Clone)]
struct Trade(i32);
trait Bet{
    fn bet(&self);
}
trait Test :Bet
    fn test(&self);
}

impl Test for Trade{
    fn test(&self){}
}

impl Trade{
    fn default(&self) -> Vec<Box<dyn Test>>{
        let mut v = Vec::new();
        let trade = Trade(0);
        v.push(Box::new(trade) as Box<dyn Test > );
        v
    }
}

这个是没有问题的。

但是,如果把Test改一下:

trait Test :Send
    fn test(&self);
}

但Clone,Sized加上去都会报错。
在这里插入图片描述
1、Send+ Sync与Clone、Sized

#[derive(Clone)]
struct Trade(i32);
trait Bet{
    fn bet(&self);
}
trait Test :Send+Sync //而不是Clone和Sized
    fn test(&self);
}

impl Test for Trade{
    fn test(&self){}
}

impl Trade{
    fn default(&self) -> Vec<Box<dyn Test>>{
        let mut v = Vec::new();
        let trade = Trade(0);
        v.push(Box::new(trade) as Box<dyn Test > );
        v
    }
}

但是,如果是,Sized、Clone组合,仍会报错。

2、object-safe trait 问题

trait object 它不仅包括指向真实对象的指针,还包括一个指向虚函数表的指针。因此,并不是所有的trait都能作为trait对象使用的。

只有 对象安全(object safe)的 trait 才可以组成 trait 对象。trait的方法满足以下两条要求才是对象安全的:

(1)返回值类型不为 Self
(2)方法没有任何泛型类型参数

典型的安全对象trait的案例:Clone trait Clone是非对象安全的,所以不能作为trait对象。

 trait Clone{
    fn clone(&self) ->Self
}

因为clone()返回Self类型,不符合上面的规则(1)。所以尽管你对你实现Clone
trait的对象调用clone()方法,但是,你不能把&Clone带到任何的地方去。

3、关于trait与泛型,struct结合, 一个更进一步的例子

例子: 有一个Manager,Empylee,他们都共同实现Earn(赚钱的能力) trait。
里面有一个问题:当抽像变成具体时,可能在编译时无法确定对象大小。


pub trait Earn: Send + Sync {
    fn earn(&self);
}

#[derive(Debug, Clone)]
struct Manager<T>
where
    T: Earn,
{
    people: Vec<Box<T>>,
}

trait Run {
    fn run(&self);
}
#[derive(Debug, Clone)]
struct Employee(i32);

impl Earn for Employee {
    fn earn(&self) {}
}

impl<T: Earn> Earn for Manager<T> {
    fn earn(&self) {}
}

//
impl<T: Earn> Manager<T> {
    fn make_employees(&self) -> Vec<Box<dyn Earn>> {
        let mut v = Vec::new();
        let e = Employee(0);
        println!("e:{:?}", e);
        v.push(Box::new(e) as Box<dyn Earn>); // as Box<dyn Earn>);
        v
    }

    fn make_managers(&self) -> Vec<Box<dyn Earn>> {
        let mut v = Vec::new();
        {
            // problem :把抽像变具体
            let e = self.make_employees();
            let manager = Manager{ people: e };
        }

        // ok
        let e = Employee(0);
        let manager = Manager {
            people: vec![Box::new(e)],
        };

        v.push(Box::new(manager) as Box<dyn Earn>);
        v
    }
}
fn main() {
    // let t = Trade(0);
    // let v = t.to_vec();
    println!("ok");
}

关于trait更进一步的了解,可以参考,写得不错:

https://zhuanlan.zhihu.com/p/127365605

4、一个有意思的库: DynClone
在github上,DynClone好象想做些不同的事。

https://github.com/dtolnay/dyn-clone

如:

use dyn_clone::DynClone;

trait MyTrait: DynClone {
    fn recite(&self);
}

impl MyTrait for String {
    fn recite(&self) {
        println!("{} ♫", self);
    }
}

fn main() {
    let line = "The slithy structs did gyre and gimble the namespace";

    // Build a trait object holding a String.
    // This requires String to implement MyTrait and std::clone::Clone.
    let x: Box<dyn MyTrait> = Box::new(String::from(line));

    x.recite();

    // The type of x2 is a Box<dyn MyTrait> cloned from x.
    let x2 = dyn_clone::clone_box(&*x);

    x2.recite();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值