我有一个 trait 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),
}
}
}
Run Code Online (Sandbox Code Playgroud)
它有效,但into_enum. 随着变体数量的增加,功能也会增加。有没有更简单的方法来做到这一点?感觉它应该是一个班轮!
我最近想要类似的东西。我不能为您提供一句简短的话,而是一个可以自动生成相应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),
);
Run Code Online (Sandbox Code Playgroud)
这样一来,只有一个地方可以维持所有的可能性,其他的一切都是生成的。也许连板条箱 enum_dispatch都有帮助。
题外话:真的应该这样吗into_enum(self)->Box<dyn Foo>?难道不应该是这样的吗as_foo(&self)->&dyn Foo?
使用enum_dispatch板条箱,您可以写
#[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),
}
Run Code Online (Sandbox Code Playgroud)
得到一个生成的impl Foo for Foos. 然后您可以简单地转换Foos为.Box<dyn Foo>Box::new
这种方法有一个潜在的缺点:Box::new(Foos::A(FooA))包含 a Foos,而不是 an FooA,因此它会产生动态调度 from dyn FootoFoos和enum调度 from Foosto的开销FooA。
另一方面,既然您拥有impl Foo for Foos: 在您本应使用的任何地方,您就Box<dyn Foo>可以直接使用Foos,这在各方面都应该更有效。