【问题标题】:Converting an enum where all variants implement the same trait to a box in Rust?将所有变体实现相同特征的枚举转换为 Rust 中的框?
【发布时间】:2023-03-03 08:53:23
【问题描述】:

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

【问题讨论】:

  • "感觉应该是单排!"主要意见?如果你愿意,你可以为 Rust 创建 RFC。
  • 另外,为什么不impl Foo for Foos
  • @Stargateur Foo 有很多方法,我不想对每个枚举变体进行匹配。
  • 是的,我认为有一个关键字在为此做准备,但宏仍然可以很好地完成这项工作。

标签: enums rust traits


【解决方案1】:

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::newFoos 转换为Box&lt;dyn Foo&gt;

这种方法有一个潜在的缺点:Box::new(Foos::A(FooA)) 包含Foos,而不是FooA,因此它会产生从dyn FooFoos 的动态调度和@987654333 的开销@从Foos调度到FooA

另一方面,现在您有了impl Foo for Foos:在您本来可以使用Box&lt;dyn Foo&gt; 的任何地方,您都可以直接使用Foos,这在各个方面都应该更有效。

【讨论】:

    【解决方案2】:

    我最近想要类似的东西。我不能为您提供单行代码,而是自动生成相应的 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)-&gt;Box&lt;dyn Foo&gt;吗?不应该是as_foo(&amp;self)-&gt;&amp;dyn Foo之类的吗?

    【讨论】:

    • 对不起,into_enum 本来是into_box,我的错。我已经更新了这个问题。有趣的是你可以返回&amp;dyn,我不知道。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2021-01-04
    • 2019-11-25
    • 2019-05-24
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多