dynamic - 是否可以将特征对象转换为另一个特征对象?
问题描述
我尝试了以下代码:
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
--> 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>`
我声明了两个特征和一个名为的类型MyType
,并为MyType
. 我创建了一个新的 trait 对象TraitA
,MyType
我称之为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 编程语言提到过它。无论如何,您似乎需要知道具体类型才能从Any
该具体类型进行转换,然后再转换为 trait 对象。
解决方案
另一种选择是创建一个同时使用TraitA
和TraitB
作为超特征并为每种类型提供强制转换的特征:
trait TraitC: TraitA + TraitB {
fn as_trait_a(&self) -> &dyn TraitA;
fn as_trait_b(&self) -> &dyn TraitB;
}
然后MyType
实现它:
impl TraitC for MyType {
fn as_trait_a(&self) -> &dyn TraitA {
self
}
fn as_trait_b(&self) -> &dyn TraitB {
self
}
}
一旦你这样做了,你就可TraitC
以为你Box
和你的程序逻辑使用两者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());
let a: &dyn TraitA = c.as_trait_a();
a.say_hello();
let b: &dyn TraitB = c.as_trait_b();
b.say_hello();
}
如果A
并且B
确实属于一起,这更好地代表了这一点,并且如果您愿意,您仍然可以自由地单独使用它们。
推荐阅读
- machine-learning - 这些数字中的每一个在暗网中意味着什么?
- java - 使用Java字符串方法替换字符串中的字符
- javascript - Javascript - 橄榄球积分计算器
- ios - 如何识别ios设备中的唯一ID?
- c# - 如果在 lambda C# 中为 null,则为默认值
- java - 能不能用m个开关把所有的灯泡都转一下
- python - Python @property 用于编辑配置文件
- mysql - 无法使用 MySQL 安装程序或控制面板卸载 MySQL 服务器 8.0.13
- node.js - “npm ERR!code ELIFECYCLE”错误 Heroku 部署
- android - 使用 PdfRenderer 类渲染的 Pdf 显示质量很差的图像。怎么修?