我具有特征Foo
,具有某些实现,以及枚举Foos
,每个实现具有一个变体。我希望能够将我的枚举转换为Box<dyn Foo>
。
这是我当前的解决方案:
trait Foo {}
struct FooA {}
impl Foo for FooA {}
struct FooB {}
impl Foo for FooB {}
struct FooC {}
impl Foo for FooC {}
enum Foos {
A(FooA),
B(FooB),
C(FooC),
}
impl Foos {
fn into_box(self) -> Box<dyn Foo> {
match self {
Foos::A(foo) => Box::new(foo),
Foos::B(foo) => Box::new(foo),
Foos::C(foo) => Box::new(foo),
}
}
}
它有效,但是into_enum
中有很多样板。随着变体数量的增加,功能也会随之增加。有没有更简单的方法可以做到这一点?感觉应该是一根衬板!
答案 0 :(得分:3)
我最近想要类似的东西。我无法为您提供单一代码,而是一个宏,该宏会自动生成相应的match
臂以及随后的enum
变体:
macro_rules! impl_foos{($($enumvariant: ident($foo: ty),)*) => {
enum Foos {
$($enumvariant($foo),)*
}
impl Foos {
fn into_enum(self) -> Box<dyn Foo> {
match self {
$(Foos::$enumvariant(foo) => Box::new(foo),)*
}
}
}
}}
impl_foos!(
A(FooA),
B(FooB),
C(FooC),
);
这样,只有一个地方可以维护所有可能性,其他所有东西都可以生成。甚至crate enum_dispatch都有帮助。
题外话:真的应该是into_enum(self)->Box<dyn Foo>
吗?应该不是像as_foo(&self)->&dyn Foo
这样的东西吗?
答案 1 :(得分:3)
使用enum_dispatch
crate,您可以写
let o = {
fn: {
a: function() {
this.b();
},
b: function() { }
}
};
获取生成的#[macro_use]
extern crate enum_dispatch;
#[enum_dispatch]
trait Foo {}
struct FooA {}
impl Foo for FooA {}
struct FooB {}
impl Foo for FooB {}
struct FooC {}
impl Foo for FooC {}
#[enum_dispatch(Foo)]
enum Foos {
A(FooA),
B(FooB),
C(FooC),
}
。然后,您可以使用简单的impl Foo for Foos
将Foos
转换为Box<dyn Foo>
。
此方法有一个潜在的缺点:Box::new
包含一个Box::new(Foos::A(FooA))
,而不是一个Foos
,因此它将招募来自FooA
的两个动态调度的开销。到dyn Foo
并将Foos
从enum
分发到Foos
。
另一方面,既然您拥有FooA
:在将要使用impl Foo for Foos
的任何地方,您将可以直接使用Box<dyn Foo>
,这样做应该更有效各种方式。