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

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

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

这里我做了一个非常简单的例子:

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 指针。 有没有办法转换克隆的共享指针?

methods as_a and as_b can't know self is actually an Rc pointer.

事实上,那不是真的! a rarely used feature 允许将 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> (only Clone). One way to fix this is to simply clone ab before passing it into these methods. This also means that you don't need to clone the self inside the method. (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();

使用仅夜间功能 arbitrary_self_types,可以使 as_aas_b 将自己视为 &Rc<Self>(这对我来说很奇怪,因为它是一个参考供参考)。这允许在不移动 ab 的情况下调用 ab.as_a()。这种方法的唯一问题是 TraitAB is no longer object-safe1, so Rc<dyn TraitAB> no longer works. (playground link).


  1. 根据 the 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 的任何理由,但您可以扩展和实现 TraitATraitB Rc<MyType> 还有。

This is a working example 实现了 TraitATraitB 的功能。