簡體   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