繁体   English   中英

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

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

这是Rust dynamic cast trait object between different taits的后续问题。 当我们对特征对象使用引用时,那里提供的解决方案非常有效,但这次我试图对Rc指针做同样的事情。 例如

  • 我有一个名为TraitAB的超级特征和两个名为TraitATraitB的特征
  • 因此,当我第一次创建TraitAB类型的特征对象而不是使用Box时,现在我使用Rc指针。
  • 我需要一个TraitA类型的变量作为ab的引用

在这里我做了一个非常小的例子:

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();
    }
}

但这不起作用。 根据错误信息:

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_aas_b无法知道 self 实际上是一个Rc指针。 有没有办法转换克隆的共享指针?

方法as_aas_b无法知道 self 实际上是一个Rc指针。

其实,那不是真的! 一个很少使用的功能允许将self视为各种标准类型的引用( Rc<Self>Box<Self>等)。

这意味着您可以将TraitAB重写为

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

不幸的是,正如所写的那样, as_aas_b移动self: Rc<Self> ,因为Rc<T> 没有实现Copy (只有Clone )。 解决此问题的一种方法是在将ab传递给这些方法之前简单地克隆它。 这也意味着您不需要在方法内部克隆self (游乐场链接)

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();

使用仅夜间功能arbitrary_self_types ,可以使as_aas_b将 self 视为&Rc<Self> (这对我来说看起来很奇怪,因为它是对引用的引用)。 这允许在不移动ab的情况下调用ab.as_a() 这种方法的唯一问题是TraitAB 不再是对象安全的1 ,因此Rc<dyn TraitAB>不再有效。 (游乐场链接)


  1. 根据tracking issue for arbitrary self types ,对象安全问题仍然悬而未决。 我不太确定现在的规则是什么。

您需要在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();
    }
}

顺便说一句,我看不出有任何理由让TraitAB扩展TraitA + TraitB ,但您也可以为Rc<MyType>扩展和实现TraitATraitB

这是一个工作示例,其中包含TraitATraitB的已实现功能。

暂无
暂无

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

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