问题
This question is related to Rust: Clone and Cast Rc pointer
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 implementsTraitA
andTraitB
. - The goal is to have a trait object
TraitA
be able to get casted toTraitB
and viceversa. - So I uses a supertrait that holds the methods to do the conversions.
- This works great for
std::Rc
smart pointers.
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.
So, the common pattern for this kind of problems is 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>
?
Thanks
回答1:
You can work around this issue by not using a receiver in TraitAB
's casting methods (i.e. by declaring them as associated functions):
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. To make this implementation available for all types implementing TraitA
and TraitB
, you can use a generic 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.
Playground
来源:https://stackoverflow.com/questions/55959384/clone-an-rcrefcellmytype-trait-object-and-cast-it