这是一个跟进的问题: Rust dynamic cast trait object between different taits
当我们使用特征对象的引用时,那里提供的解决方案非常有效。
这次,我试图对Rc指针执行相同的操作。例如
TraitAB
的超级特质和两个名为TraitA
和TraitB
的特质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();
}
}
但这不起作用。根据错误消息:
xx | fn as_a(&self) -> Rc<dyn TraitA> {Rc::clone(self)}
| ^^^^ expected struct `std::rc::Rc`, found struct `MyType`
|
= note: expected type `&std::rc::Rc<dyn TraitA>`
found type `&MyType`
方法as_a
和as_b
不知道self实际上是一个Rc指针。
有没有办法对克隆的共享指针进行强制转换?
谢谢
答案 0 :(得分:2)
方法as_a和as_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>
doesn't implement Copy
(仅Rc<T>
)以来就移动了Clone
。解决此问题的一种方法是在将ab
传递给这些方法之前,先对其进行克隆。这也意味着您无需在方法内部克隆self
。 (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_a
和as_b
取为&Rc<Self>
(这对我来说很奇怪,因为它是对参考)。这样就可以在不移动ab.as_a()
的情况下调用ab
。这种方法的唯一问题是TraitAB
is no longer object-safe 1 ,因此Rc<dyn TraitAB>
不再起作用。 (playground link)。
答案 1 :(得分:1)
您需要在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 + TraitB
的任何理由,但是您也可以为TraitA
扩展和实现TraitB
和Rc<MyType>
。
您可以在Playground
中找到包含TraitA
和TraitB
的已实现功能的工作示例。