将所有变体都实现相同特征的枚举转换为 Rust 中的框?

And*_*ers 5 enums traits rust

我有一个 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. 随着变体数量的增加,功能也会增加。有没有更简单的方法来做到这一点?感觉它应该是一个班轮!

phi*_*mue 5

我最近想要类似的东西。我不能为您提供一句简短的话,而是一个可以自动生成相应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


And*_*org 5

使用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 FootoFoosenum调度 from Foosto的开销FooA

另一方面,既然您拥有impl Foo for Foos: 在您本应使用的任何地方,您就Box<dyn Foo>可以直接使用Foos,这在各方面都应该更有效。