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

时间:2019-01-05 21:58:49

标签: enums rust traits

我具有特征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中有很多样板。随着变体数量的增加,功能也会随之增加。有没有更简单的方法可以做到这一点?感觉应该是一根衬板!

2 个答案:

答案 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 FoosFoos转换为Box<dyn Foo>

此方法有一个潜在的缺点:Box::new包含一个Box::new(Foos::A(FooA)),而不是一个Foos,因此它将招募来自FooA的两个动态调度的开销。到dyn Foo并将Foosenum分发到Foos

另一方面,既然您拥有FooA:在将要使用impl Foo for Foos的任何地方,您将可以直接使用Box<dyn Foo>,这样做应该更有效各种方式。