我想知道是否可以将一个特征对象转换为另一个特征对象。
我尝试了以下代码:
trait TraitA {
fn say_hello(&self) {
self.say_hello_from_a();
}
fn say_hello_from_a(&self);
}
trait TraitB {
fn say_hello(&self) {
self.say_hello_from_b();
}
fn say_hello_from_b(&self);
}
struct MyType {}
impl TraitA for MyType {
fn say_hello_from_a(&self) {
println!("Hello from A");
}
}
impl TraitB for MyType {
fn say_hello_from_b(&self) {
println!("Hello from B");
}
}
fn main() {
let a: Box<dyn TraitA> = Box::new(MyType{});
let b: Box<dyn TraitB>;
a.say_hello();
b = a;
b.say_hello();
}
我收到以下编译错误:
error[E0308]: mismatched types
--> trait_objects.rs:34:9
|
34 | b = a;
| ^ expected trait `TraitB`, found trait `TraitA`
|
= note: expected type `std::boxed::Box<dyn TraitB>`
found type `std::boxed::Box<dyn TraitA>`
所以我试图做的是声明2个特征和一个名为 MyType 的类型。然后,我实现了MyType的两个特征。我创建了一个MyType类型的新特征对象TraitA,我将其称为 a 。但是由于 a 也实现了TraitB,所以我认为应该可以将其转换为TraitB。
还没有想出是否有可能。如果是这样,如何将特征对象a转换为TraitB。
注意:在C ++中,出于相同的目的,我通常会使用类似于std::dynamic_pointer_cast<TraitB>(a);
的东西。
谢谢
编辑: 我添加了一个示例,其中可以使用横向浇铸。
比方说,我有一个结构,其中包含一些表示某些现实生活实体的数据:
struct MyType {
let a: i32;
let b: i32;
}
这种类型的实例可以在代码库的至少两个不同部分中使用。在这两个部分上,我都需要一个名为get_final_value
的行为。
有趣的是,get_final_value的响应取决于调用它的人。
我为什么不将类型分为2个不同的类型?:从技术上讲,a
和b
属于同一类,并不是说get_final_value()
既使用了两者又使用了值来计算结果。
为什么不使用泛型/静态调度?因为MyType只是一个示例。在实际情况下,我有不同的structs
,他们都以不同的方式实现了这两个特征。
为什么不使用Any
特征?老实说,直到最近我才知道它的存在。我不记得 Rust编程语言书中提到它的情况。无论如何,似乎您需要了解具体类型,才能将Any转换为该具体类型,然后转换为trait对象。
答案 0 :(得分:2)
另一种选择可能是创建同时使用TraitA和TraitB作为特征的特征,并为每种类型提供强制转换:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="./index.css" />
</head>
<body>
<audio autoplay controls>
<source src="./biker.mp3" type="audio/mpeg">
</audio>
<main>
<div class="bike">
<img src="./public/images/biker1.png">
</div>
</main>
</body>
</html>
然后让MyType实现它:
trait TraitC : TraitA + TraitB {
fn as_trait_a(&self) -> &dyn TraitA;
fn as_trait_b(&self) -> &dyn TraitB;
}
一旦这样做,您就可以对Box使用TraitC,并同时使用TraitA和TraitB的程序逻辑。
主要示例以显示各种使用方式:
impl TraitC for MyType {
fn as_trait_a(&self) -> &dyn TraitA {self}
fn as_trait_b(&self) -> &dyn TraitB {self}
}
如果A和B确实确实属于在一起,那么这更好地表示了这一点,并且仍然让您可以自由地根据需要单独使用它们。
答案 1 :(得分:1)
使用Box<MyType>
代替Box<dyn Trait>
解决了这个问题。
fn main() {
let a = Box::new(MyType {});
TraitA::say_hello(&*a);
TraitB::say_hello(&*a);
}
在这种情况下,无需使用特征对象。 Rust具有与C ++不同的范例。在大多数情况下,通常可以使用通用类型来解决问题。 如果您的问题确实适合使用特征对象解决,则可以参考OOP chapter in the book。