简体   繁体   English

如何克隆一个 Rc 特征对象并将其转换为另一个特征对象?

[英]How do I clone a Rc trait object and cast it to another trait object?

This is a follow up question from Rust dynamic cast trait object between different taits .这是Rust dynamic cast trait object between different taits的后续问题。 The solution provided there works really well when we use references for trait objects, but this time I am trying to do the same with Rc pointers.当我们对特征对象使用引用时,那里提供的解决方案非常有效,但这次我试图对Rc指针做同样的事情。 For example例如

  • I have a super trait named TraitAB and 2 traits named TraitA and TraitB我有一个名为TraitAB的超级特征和两个名为TraitATraitB的特征
  • So when I first create a trait object of type TraitAB instead of using a Box , now I use an Rc pointer.因此,当我第一次创建TraitAB类型的特征对象而不是使用Box时,现在我使用Rc指针。
  • I need a variable of type TraitA to be a reference of ab我需要一个TraitA类型的变量作为ab的引用

Here I made a very minimal example:在这里我做了一个非常小的例子:

use std::rc::Rc;

trait TraitAB: TraitA + TraitB {
    fn as_a(&self) -> Rc<dyn TraitA>;
    fn as_b(&self) -> Rc<dyn TraitB>;
}

trait TraitA {}
trait TraitB {}

struct MyType {}

impl TraitAB for MyType {
    fn as_a(&self) -> Rc<dyn TraitA> {
        Rc::clone(self)
    }
    fn as_b(&self) -> Rc<dyn TraitB> {
        Rc::clone(self)
    }
}

impl TraitA for MyType {}
impl TraitB for MyType {}

fn main() {
    let a: Rc<dyn TraitA>;
    let b: Rc<dyn TraitB>;
    {
        let mut ab: Rc<dyn TraitAB> = Rc::new(MyType {});
        a = ab.as_a();
        b = ab.as_b();
    }
}

This doesn't work though.但这不起作用。 According to the error messages:根据错误信息:

error[E0308]: mismatched types
  --> src/main.rs:15:19
   |
15 |         Rc::clone(self)
   |                   ^^^^ expected struct `std::rc::Rc`, found struct `MyType`
   |
   = note: expected reference `&std::rc::Rc<dyn TraitA>`
              found reference `&MyType`

error[E0308]: mismatched types
  --> src/main.rs:18:19
   |
18 |         Rc::clone(self)
   |                   ^^^^ expected struct `std::rc::Rc`, found struct `MyType`
   |
   = note: expected reference `&std::rc::Rc<dyn TraitB>`
              found reference `&MyType`

as_a and as_b can't know self is actually an Rc pointer. as_aas_b无法知道 self 实际上是一个Rc指针。 Is there a way to do the cast of a cloned shared pointer?有没有办法转换克隆的共享指针?

methods as_a and as_b can't know self is actually an Rc pointer.方法as_aas_b无法知道 self 实际上是一个Rc指针。

Actually, that's not true!其实,那不是真的! There's a rarely used feature that allows self to be taken as various standard kinds of references ( Rc<Self> , Box<Self> , etc.).一个很少使用的功能允许将self视为各种标准类型的引用( Rc<Self>Box<Self>等)。

That means that you can rewrite your TraitAB as这意味着您可以将TraitAB重写为

trait TraitAB : TraitA + TraitB {
    fn as_a(self: Rc<Self>) -> Rc<dyn TraitA>;
    fn as_b(self: Rc<Self>) -> Rc<dyn TraitB>;
}

Unfortunately, as written, as_a and as_b move self: Rc<Self> , since Rc<T> doesn't implement Copy (only Clone ).不幸的是,正如所写的那样, as_aas_b移动self: Rc<Self> ,因为Rc<T> 没有实现Copy (只有Clone )。 One way to fix this is to simply clone ab before passing it into these methods.解决此问题的一种方法是在将ab传递给这些方法之前简单地克隆它。 This also means that you don't need to clone the self inside the method.这也意味着您不需要在方法内部克隆self (playground link) (游乐场链接)

let ab: Rc<dyn TraitAB> = Rc::new(MyType{});
let _a: Rc<dyn TraitA> = ab.clone().as_a();
let _b: Rc<dyn TraitB> = ab.clone().as_b();

Using the nightly-only feature arbitrary_self_types , it's possible to make as_a and as_b take self as &Rc<Self> (which looks weird to me since it's a reference to a reference).使用仅夜间功能arbitrary_self_types ,可以使as_aas_b将 self 视为&Rc<Self> (这对我来说看起来很奇怪,因为它是对引用的引用)。 This allows ab.as_a() to be called without moving ab .这允许在不移动ab的情况下调用ab.as_a() The only problem with this approach is that TraitAB is no longer object-safe 1 , so Rc<dyn TraitAB> no longer works.这种方法的唯一问题是TraitAB 不再是对象安全的1 ,因此Rc<dyn TraitAB>不再有效。 (playground link) . (游乐场链接)


  1. According to the tracking issue for arbitrary self types , the object safety question is still open.根据tracking issue for arbitrary self types ,对象安全问题仍然悬而未决。 I'm not really sure what the rules are right now.我不太确定现在的规则是什么。

You need to implement TraitAB on RC<MyType> :您需要在RC<MyType>上实施TraitAB

use std::rc::Rc;

trait TraitAB {
    fn as_a(&self) -> Rc<dyn TraitA>;
    fn as_b(&self) -> Rc<dyn TraitB>;
}

trait TraitA {}
trait TraitB {}

struct MyType {}

impl TraitAB for Rc<MyType> {
    fn as_a(&self) -> Rc<dyn TraitA> {
        Rc::clone(self) as Rc<dyn TraitA>
    }
    fn as_b(&self) -> Rc<dyn TraitB> {
        Rc::clone(self) as Rc<dyn TraitB>
    }
}

impl TraitA for MyType {}
impl TraitB for MyType {}

fn main() {
    let a: Rc<dyn TraitA>;
    let b: Rc<dyn TraitB>;
    {
        let mut ab: &TraitAB = &Rc::new(MyType {});
        a = ab.as_a();
        b = ab.as_b();
    }
}

By the way, I don't see any reason for TraitAB to extend TraitA + TraitB , but you can extend and implement TraitA and TraitB for Rc<MyType> as well.顺便说一句,我看不出有任何理由让TraitAB扩展TraitA + TraitB ,但您也可以为Rc<MyType>扩展和实现TraitATraitB

This is a working example with the implemented functions for TraitA and TraitB . 这是一个工作示例,其中包含TraitATraitB的已实现功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM