是否可以将特征对象投射到另一个特征对象? [英] Is it possible to cast a trait object to another trait object?
问题描述
我尝试了以下代码:
trait TraitA {
fn say_hello( & self){
self.say_hello_from_a();
}
fn say_hello_from_a(& self);
}
特质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!(您好,A);
}
}
impl MyType的TraitB {
fn say_hello_from_b(& self){
println!(来自B的Hello);
}
}
fn main(){
let a:Box< dyn TraitA> = Box :: new(MyType {});
let b:Box< dyn TraitB> ;;
a.say_hello();
b = a;
b.say_hello();
}
我收到以下编译错误:
错误[E0308]:类型不匹配的
-> src / main.rs:34:9
|
34 | b = a;
| ^预期特征`TraitB`,发现特征`TraitA`
|
=注意:预期的struct`std :: boxed :: Box< dyn TraitB>`
找到了struct`std :: boxed :: Box< dyn TraitA>`
我声明了两个特征和一个名为 MyType
的类型,并为<$ c实现了这两个特征$ c> MyType 。我创建了类型为 MyType
的新特征对象 TraitA
,我将其称为 a
。由于 a
还实现了 TraitB
,我认为应该可以将其转换为 TraitB
。
我什至不知道是否有可能。如果是,如何将特征对象 a
转换为 TraitB
?
在C ++中,出于相同的目的,我会使用类似于 std :: dynamic_pointer_cast< TraitB>(a);
的东西。
这里是一个我可以使用横向强制转换的例子:我有一个结构,里面有一些数据代表了现实生活中的实体:
struct MyType {
a:i32,
b:i32,
}
这种类型的实例至少可以在代码库的两个不同部分中使用。在这两个部分上,我都需要一个名为 get_final_value
的行为。
有趣的是, get_final_value
的响应方式取决于调用者。
-
我为什么不将类型分成两个不同的类型?:从技术上讲,按设计,
a
和b
在一起,并不是说get_final_value()
使用这两个值来计算结果。 -
为什么不使用泛型/静态调度?因为
MyType
只是一个例子。在实际情况下,我具有不同的结构,它们全部以不同的方式实现这两个特征。 -
为什么不使用
Any
特质?老实说,直到最近我才知道它的存在。我不记得 Rust编程语言提到过它。无论如何,似乎您需要知道具体类型才能将任何
转换为该具体类型,然后再转换为trait对象。
另一个选择是创建同时使用 TraitA
和 TraitB
作为特征,并为每种类型提供强制转换:
trait TraitC:TraitA + TraitB {
fn as_trait_a(& self)-> & dyn特性
fn as_trait_b(& self)-> & dyn特性B;
}
然后有 MyType
实现它:
iType TraitC for MyType {
fn as_trait_a(& self)-> & dyn TraitA {
self
}
fn as_trait_b(& self)-> & dyn特性B {
self
}
}
这样,您就可以在 Box
中使用 TraitC
,并且在程序逻辑中同时使用 TraitA
和 TraitB
一起。
主要示例显示了多种使用方式:
fn test_a(a:& TraitA){
a.say_hello();
}
fn test_b(b:& TraitB){
b.say_hello();
}
fn main(){
let c:Box< dyn TraitC> = Box :: new(MyType {});
TraitA :: say_hello(& * c);
TraitB :: say_hello(& * c);
c.as_trait_a()。say_hello();
c.as_trait_b()。say_hello();
test_a(c.as_trait_a());
test_b(c.as_trait_b());
让a:& dyn TraitA = c.as_trait_a();
a.say_hello();
让b:& dyn特性B = c.as_trait_b();
b.say_hello();
}
如果 A
和 B
确实是真正属于在一起的,这更好地表示了这一点,并且仍然让您可以自由地根据需要单独使用它们。 / p>
I tried the following code:
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();
}
I get the following compilation error:
error[E0308]: mismatched types
--> src/main.rs:34:9
|
34 | b = a;
| ^ expected trait `TraitB`, found trait `TraitA`
|
= note: expected struct `std::boxed::Box<dyn TraitB>`
found struct `std::boxed::Box<dyn TraitA>`
I declared two traits and a type called MyType
and implemented both traits for MyType
. I created a new trait object TraitA
of type MyType
which I called a
. Since a
also implements TraitB
, I thought it should be able to be casted as TraitB
.
I haven't figured out if it's even possible. If it is, how can I cast trait object a
into TraitB
?
In C++, I would use something similar to std::dynamic_pointer_cast<TraitB>(a);
for the same purpose.
Here's an example of a case where I could use lateral casting: I have a struct with some data inside that represents some real life entity:
struct MyType {
a: i32,
b: i32,
}
Instances of this type can be used in at least two different parts of the code base. On both parts I need a behavior called get_final_value
.
The interesting part is that get_final_value
should respond differently depending on who called it.
Why don't I split the type into two different ones?: Technically, by design,
a
andb
belong together, not to say thatget_final_value()
uses both values to compute the result.Why not use generics/static dispatch? Because
MyType
is just one example. In the real case I have different structs, all of them implementing both traits in different ways.Why not use
Any
trait? To be honest, I didn't know of it's existence until recently. I don't recall The Rust Programming Language mentioning it. Anyway, it seems you need to know the concrete type to do a cast fromAny
to that concrete type and then to the trait object.
Another option is to create a trait that uses both TraitA
and TraitB
as supertraits and provides a cast to each type:
trait TraitC: TraitA + TraitB {
fn as_trait_a(&self) -> &dyn TraitA;
fn as_trait_b(&self) -> &dyn TraitB;
}
Then have MyType
implement it:
impl TraitC for MyType {
fn as_trait_a(&self) -> &dyn TraitA {
self
}
fn as_trait_b(&self) -> &dyn TraitB {
self
}
}
Once you do that, you can use TraitC
for your Box
and your program logic that uses both TraitA
and TraitB
together.
Sample main to show various ways to use:
fn test_a(a: &TraitA) {
a.say_hello();
}
fn test_b(b: &TraitB) {
b.say_hello();
}
fn main() {
let c: Box<dyn TraitC> = Box::new(MyType {});
TraitA::say_hello(&*c);
TraitB::say_hello(&*c);
c.as_trait_a().say_hello();
c.as_trait_b().say_hello();
test_a(c.as_trait_a());
test_b(c.as_trait_b());
let a: &dyn TraitA = c.as_trait_a();
a.say_hello();
let b: &dyn TraitB = c.as_trait_b();
b.say_hello();
}
If A
and B
do truly belong together, this better represents that and still gives you the freedom to use them separately if you desire.
这篇关于是否可以将特征对象投射到另一个特征对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!