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

Converting an enum where all variants implement the same trait to a box in Rust?

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

我最近想要类似的东西。我无法为您提供单行代码,但可以自动生成相应的 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 吗?

有了enum_dispatch crate,你可以写

#[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。然后,您可以使用 Box::new.

Foos 转换为 Box<dyn Foo>

这种方法有一个潜在的缺点:Box::new(Foos::A(FooA)) 包含 Foos,而不是 FooA,因此它会产生来自 [=19 的动态调度的开销=] 到 FoosenumFoos 发送到 FooA.

另一方面,现在你有了 impl Foo for Foos: 任何你会使用 Box<dyn Foo> 的地方,你将能够直接使用 Foos,这应该更各方面都很高效。