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

问题描述 投票:0回答:2

这是来自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指针。有没有办法对克隆的共享指针进行强制转换?

casting rust smart-pointers trait-objects
2个回答
3
投票

as_aas_b方法不知道self实际上是Rc指针。

实际上,这是不正确的! 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_a as_b(仅self: Rc<Self>),Rc<T>doesn't implement Copy会移动Copy。解决此问题的一种方法是在将Clone传递给这些方法之前,先对其进行克隆。这也意味着您无需在方法内部克隆abself

(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_typesas_a取为as_b(这对我来说很奇怪,因为它是对参考的引用)。这样就可以在不移动&Rc<Self>的情况下调用ab.as_a()。这种方法的唯一问题是abTraitAB1,因此is no longer object-safe不再起作用。 Rc<dyn TraitAB>


  1. 根据(playground link),对象安全问题仍然存在。我不确定目前的规则是什么。

1
投票

您需要在the tracking issue for arbitrary self types上实现TraitAB

RC<MyType>

顺便说一句,我看不到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 + TraitBTraitATraitB

Rc<MyType>具有已实现的This is a working exampleTraitA功能。

© www.soinside.com 2019 - 2024. All rights reserved.