避免在“枚举”

时间:2019-11-27 15:25:01

标签: enums rust

我发现自己经常定义如下的enum类型:

struct Foo { }
struct Bar { }
struct Baz { }

enum MyEnum {
    Foo(Foo),
    Bar(Bar),
    Baz(Baz),
}

我发现Foo(Foo)的重复既优雅又多余。它还使初始化变得多余:

let example = MyEnum::Foo(Foo{ /* ... */ });

我想改写类似以下的伪代码:

struct Foo { }
struct Bar { }
struct Baz { }

type_enum MyEnum {
    Foo,
    Bar,
    Baz,
}

let example = MyEnum::Foo{ /* ...anything that `Foo` supports ... */ };

以上内容与C ++ 17中的std::variant非常相似。 Rust支持类似的功能吗?

2 个答案:

答案 0 :(得分:3)

enum的变体可以是struct,tuple或unit struct。因此,您可以简单地定义:

enum MyEnum {
    Foo {},
    Bar {},
    Baz {},
}

或者,如果您想将这些变体定义为独立的结构本身,我认为更惯用的“功能”方式是使用类似Either的方式:

enum Either<L, R> {
    Left(L),
    Right(R),
}

struct Foo {}
struct Bar {}

type MyEnum = Either<Foo, Bar>;

有一个同名的箱子,但是这个基本定义在大多数情况下应该足够了。

答案 1 :(得分:3)

也许您可以使用这种基于宏的解决方案:

macro_rules! type_dispatch_enum{(enum $e: ident {$($v: ident,)*}) => {
    enum $e {
        $($v($v),)*
    }
    $(
        impl From<$v> for $e {
            fn from(v: $v) -> Self {
                $e::$v(v)
            }
        }
    )+
}}

struct S1 {}
struct S2;
struct S3(usize);

type_dispatch_enum!(enum E {
    S1,
    S2,
    S3,
});

fn take_e(e: E) {}

fn main() {
    take_e(S1{}.into());
    take_e(S2.into());
    take_e(S3(5).into());
}