在Rust中具有常量值的枚举

时间:2016-04-29 02:30:05

标签: rust

我可以这样做:

enum MyEnum {
    A(i32),
    B(i32),
}

但不是这样:

enum MyEnum {
    A(123), // 123 is a constant
    B(456), // 456 is a constant
}

我可以使用单个字段为AB创建结构,然后实现该字段,但我认为可能有一种更简单的方法。有没有?

4 个答案:

答案 0 :(得分:35)

回答这个问题的最好方法是找出为什么你想要枚举中的常量:你只是将一个值与每个变体相关联,或者你是否希望每个变体 该值(如C或C ++中的enum)?

对于第一种情况,将枚举变量保留为无数据可能更有意义,并且可以创建一个函数:

enum MyEnum {
    A,
    B,
}

impl MyEnum {
    fn value(&self) -> i32 {
        match *self {
            MyEnum::A => 123,
            MyEnum::B => 456,
        }
    }
}
// call like some_myenum_value.value()

这种方法可以多次应用,以将许多单独的信息与每个变体相关联,例如,也许你也想要一个.name() -> &'static str方法。

或者,对于第二种情况,您可以像C / C ++一样分配显式标记值:

enum MyEnum {
    A = 123,
    B = 456,
}

这可以match以相同的方式进行,但也可以强制转换为整数MyEnum::A as i32。 (请注意,像MyEnum::A | MyEnum::B这样的计算在Rust中不会自动合法:枚举具有特定值,它们不是位标志。)

答案 1 :(得分:5)

可以使用结构和associated constants来增强创建具有恒定值的“枚举”。 这类似于bitflags这样的板条箱的工作方式以及产生的结果。

另外,要防止直接实例化MyEnum,可以用#[non_exhaustive]对其进行标记。

#[non_exhaustive]
struct MyEnum;

impl MyEnum {
    pub const A: i32 = 123;
    pub const B: i32 = 456;
}

然后,您可以通过访问MyEnum::AMyEnum::B来简单地使用“枚举”。

答案 2 :(得分:3)

关注这一点的人可能偶然发现FromPrimitive的引入和弃用。可能在此处有用的替代品是enum_primitive。它允许您使用类似C的枚举,并在数字和逻辑表示之间进行转换:

#[macro_use]
extern crate enum_primitive;
extern crate num;

use num::FromPrimitive;

enum_from_primitive! {
    #[derive(Debug, PartialEq)]
    enum FooBar {
        Foo = 17,
        Bar = 42,
        Baz,
    }
}

fn main() {
    assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
    assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
    assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
    assert_eq!(FooBar::from_i32(91), None);
}

答案 3 :(得分:1)

另一种选择是enum-map条板箱。这样就可以为枚举记录分配值。而且,您可以将此宏用于不同的值类型。

#[macro_use]
extern crate enum_map;

use enum_map::EnumMap;

#[derive(Debug, Enum)]
enum Example {
    A,
    B,
    C,
}

fn main() {
    let mut map = enum_map! {
        Example::A => 1,
        Example::B => 2,
        Example::C => 3,
    };
    map[Example::C] = 4;

    assert_eq!(map[Example::A], 1);

    for (key, &value) in &map {
        println!("{:?} has {} as value.", key, value);
    }
}