在我正在研究的项目中,存在此对象:
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
或SomeLocalTrait
之类的任意特征。
我也尝试过使用Box::<T>::new()
之类的turbo鱼,但无济于事。编译器抱怨T
并没有告诉编译器它只是一个特征。有?Sized
,但我找不到?IAmTrait
。新的Rust 2018 impl Trait
语法以类似的方式失败。
我现在通过使用宏创建函数来解决此问题。所以我有dispatch_debug
或dispatch_cool_trait
。本质上是重新实现泛型接口。由于我们想将其用于不相关的特征,因此我无法使用某种形式的父代特征。 Debug
或Display
与我们将创建的任何特征都不相关。
有更好的方法吗?在一个完美的世界中,我们将拥有一个dispatch
函数或方法,该函数或方法将使我们能够说:
action(foo.dispatch<SomeTrait>())
这是一个沙盒,其中显示了简化版本以开始对话。 https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7b739ab11da15ec793ee46c2d8ac47fc
答案 0 :(得分:0)
如果您愿意放弃枚举,则可以使用其他特征来进行调度:
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);
}