简体   繁体   English

克隆RC <RefCell<MyType> 特征对象并进行投射

[英]Clone an Rc<RefCell<MyType> trait object and cast it

This question is related to Rust: Clone and Cast Rc pointer 这个问题与Rust有关:Clone和Cast Rc指针

Let's say I have this piece of code which works fine: 假设我有一段运行良好的代码:

use std::rc::Rc;

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

trait TraitA {}
trait TraitB {}

struct MyType {}

impl TraitAB for MyType {
    fn as_a(self: Rc<Self>) -> Rc<dyn TraitA> {self}
    fn as_b(self: Rc<Self>) -> Rc<dyn TraitB> {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.clone().as_a();
        b = ab.clone().as_b();
    }
    // Use a and b.
}

Explaining the code a bit: 解释一下代码:

  • I have type called MyType which implements TraitA and TraitB . 我有一个叫做MyType类型,它实现了TraitATraitB
  • The goal is to have a trait object TraitA be able to get casted to TraitB and viceversa. 目标是使特征对象TraitA能够TraitB转换为TraitB ,反之亦然。
  • So I uses a supertrait that holds the methods to do the conversions. 因此,我使用一个上级特征来保存进行转换的方法。
  • This works great for std::Rc smart pointers. 这对于std::Rc智能指针非常std::Rc

So far so good. 到现在为止还挺好。 But now I need a mutable reference of both a and b , but since a and b are actually the same type instance, Rust won't let me have 2 mutable references of the same thing. 但现在我需要两者的可变参考ab ,但由于ab实际上是同一类型的情况下,防锈不会让我有一样的东西2个可变引用。

So, the common pattern for this kind of problems is std::cell::RefCell . 因此,此类问题的常见模式是std::cell::RefCell

Note: I believe this pattern is correct in this particular case because it's a common interior mutability problem. 注意:我相信这种模式在这种特殊情况下是正确的,因为这是一个常见的内部可变性问题。 I'm not willing to actually change the reference, but the internal state of the type only. 我不愿意实际更改引用,而只更改类型的内部状态。

So following that idea I changed the following lines: 因此,按照这个想法,我更改了以下几行:

trait TraitAB : TraitA + TraitB {
    fn as_a(self: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitA>>;
    fn as_b(self: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitB>>;
}
//...
let mut ab: Rc<RefCell<dyn TraitAB>> = Rc::new(RefCell::new(MyType{}));

But this changes won't compile. 但是,此更改将无法编译。 After some reading, I found that self can only be: 经过一番阅读,我发现自我只能是:

  • self: Self // self
  • self: &Self // &self
  • self: &mut Self // &mut self
  • self: Box<Self> // No short form
  • self: Rc<Self> // No short form / Recently supported

So this means I can't use 所以这意味着我不能使用

self: Rc<RefCell<Self>>

for the self param. 对于自我的参数。

So, the main question is: Is there a way to cast an Rc<RefCell<TraitA>> to an Rc<RefCell<TraitB> ? 因此,主要问题是:是否有一种方法可以将Rc<RefCell<TraitA>>转换为Rc<RefCell<TraitB> Thanks 谢谢

You can work around this issue by not using a receiver in TraitAB 's casting methods (ie by declaring them as associated functions ): 您可以通过不在 TraitAB的转换方法中使用接收器(即,通过将它们声明为关联函数 )来解决此问题:

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

The trait can then be implemented as 然后可以将特征实现为

impl TraitAB for MyType {
    fn as_a(it: Rc<RefCell<MyType>>) -> Rc<RefCell<dyn TraitA>> {it}
    fn as_b(it: Rc<RefCell<MyType>>) -> Rc<RefCell<dyn TraitB>> {it}
}

These functions can then be called using the fully qualified syntax. 然后可以使用完全限定的语法来调用这些函数。

a = TraitAB::as_a(ab.clone());
b = TraitAB::as_b(ab.clone());

The TraitAB implementation for all types will be the same. 所有类型的TraitAB实现都是相同的。 To make this implementation available for all types implementing TraitA and TraitB , you can use a generic impl : 为了使该实现可用于实现TraitATraitB所有类型,可以使用通用的impl

impl<T: TraitA + TraitB + 'static> TraitAB for T {
    fn as_a(it: Rc<RefCell<T>>) -> Rc<RefCell<dyn TraitA>> {it}
    fn as_b(it: Rc<RefCell<T>>) -> Rc<RefCell<dyn TraitB>> {it}
}

Note that T: 'static because the trait objects in the function return types have an implicit 'static lifetime bound. 注意T: 'static因为函数返回类型中的trait对象具有隐式的'static生命周期限制。

Playground 操场

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

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