在我正在处理的项目中有这个对象:
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
将代码写入函数中,以便我们可以分派(dispatch)任意特征。
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
或 SomeLocalTrait
.
我也尝试过使用像 Box::<T>::new()
这样的涡轮鱼但无济于事。编译器提示 T
不会告诉编译器它只是一个特征。有 ?Sized
但我找不到 ?IAmTrait
.新的 Rust 2018 impl Trait
语法以类似的方式失败。
我现在通过使用宏创建函数来解决这个问题。所以我有 dispatch_debug
或 dispatch_cool_trait
.本质上是重新实现泛型接口(interface)。因为我们想将它用于不相关的特征,所以我不能使用某种形式的父特征。 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);
}
关于generics - 如何在执行动态调度的 Rust 中实现泛型函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53784370/