generics - 如何在 Rust 中实现一个执行动态调度的通用函数?
问题描述
在我正在处理的一个项目中,有这个对象:
enum ContainedType {
SomeType,
OtherType,
...
}
struct OurObject {
contains: ContainedType,
...
}
impl OurObject {
pub fn unpack_sometype(self) -> AType { ... }
pub fn unpack_othertype(self) -> BType { ... }
...
}
OurObject
是以某种方式“包装”的东西的容器。每个可以打包的东西都实现了各种特征。
我们以重复的代码结束,例如:
match foo.type() {
SomeType => action(foo.unpack_sometype()),
OtherType => action(foo.unpack_othertype()),
...
}
我想将match
代码分解为一个函数,以便我们可以在任意特征上进行调度。
action(foo)
但是,我遇到了问题......
pub fn dispatch<T>(obj: OurObject) -> Box<T> {
match obj.type() {
SomeType => Box::new(obj.unpack_sometype()),
OtherType => Box::new(obj.unpack_othertype()),
...
}
}
T
这里应该代表任意特征,例如Debug
or SomeLocalTrait
。
我也尝试过使用turbofish,Box::<T>::new()
但无济于事。编译器抱怨T
说它没有告诉编译器它只是一个特征。有,?Sized
但我找不到?IAmTrait
. 新的 Rust 2018impl Trait
语法以类似的方式失败。
我现在已经通过使用宏创建函数来解决这个问题。所以我有dispatch_debug
or dispatch_cool_trait
。本质上是重新实现泛型接口。由于我们想将其用于不相关的特征,我不能使用某种形式的父特征。Debug
或者Display
与我们将创建的任何特征无关。
有没有更好的办法?在一个完美的世界里,我们会有一个dispatch
函数或方法可以让我们说:
action(foo.dispatch<SomeTrait>())
这是一个沙盒,显示了开始对话的简化版本。 https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7b739ab11da15ec793ee46c2d8ac47fc
解决方案
如果您愿意摆脱枚举,您可以使用其他特征进行调度:
trait ObjectTrait {
fn example1(&self);
fn example2(&self);
}
struct Object2<E> {
thing: E,
}
impl<E: fmt::Debug + MeaninglessNumeric> ObjectTrait for Object2<E> {
fn example1(&self) {
println!("{:?}", self.thing);
}
fn example2(&self) {
println!("{}", self.thing.numeric());
}
}
fn example3(o: &ObjectTrait) {
o.example1();
}
fn example4(o: &ObjectTrait) {
o.example2();
}
之后,你可以调整你的主要:
fn main() {
let obj1 = OurObject {
contains: ContainedType::SomeType,
};
let obj2 = OurObject {
contains: ContainedType::OtherType,
};
let obj3 = Object2 {
thing: AType { value: 5 },
};
let obj4 = Object2 {
thing: BType {
contents: "Hello, World".to_string(),
},
};
example1(obj1);
example2(obj2);
example3(&obj3);
example4(&obj4);
}
推荐阅读
- docker - 如何将 Jenkins 环境变量注入 pom.xml
- session - 如何验证 ColdFusion .cfc 页面中的有效会话和会话数据?
- c++ - 在 c++17 中过滤类型的元组
- javascript - 获取图像尺寸并将它们应用于另一个图像
- mysql - 存储过程无法按我的意愿工作
- node.js - 将 PDF 上传到 Amazon S3 并在浏览器中显示
- html - 使用高级逻辑查询 Html 层次结构
- python - pandas - 通过重复值连接列
- kubernetes - 状态集的就绪探测,而不是单个 pod/容器
- php - 在 Laravel 微服务中解码 JWT 并创建经过身份验证的用户,并与本地用户数据合并