如何枚举值与一个整数相匹配?如何枚举值与一个整数相匹配?(How do I match enum v

2019-05-12 04:48发布

我能得到这样一个枚举的整数值:

enum MyEnum {
    A = 1,
    B,
    C,
}

let x = MyEnum::C as i32;

但我似乎无法做到这一点:

match x {
    MyEnum::A => {}
    MyEnum::B => {}
    MyEnum::C => {}
    _ => {}
}

我怎么能对枚举或值要么匹配尝试转换xMyEnum

我可以看到像这对于枚举有用的功能,但它可能不存在:

impl MyEnum {
    fn from<T>(val: &T) -> Option<MyEnum>;
}

Answer 1:

您可以利用匹配警卫写的相当,但笨重,结构:

match x {
    x if x == MyEnum::A as i32 => ...,
    x if x == MyEnum::B as i32 => ...,
    x if x == MyEnum::C as i32 => ...,
    _ => ...
}

std::mem::transmute也可用于:

let y: MyEnum = unsafe { transmute(x as i8) };

但是,这需要你知道枚举的大小,这样你就可以转换为一个合适的标量第一,同时也将产生不确定的行为,如果x不是枚举的有效值。



Answer 2:

你可以得到FromPrimitive 。 使用除锈2018简化进口语法:

use num_derive::FromPrimitive;    
use num_traits::FromPrimitive;

#[derive(FromPrimitive)]
enum MyEnum {
    A = 1,
    B,
    C,
}

fn main() {
    let x = 2;

    match FromPrimitive::from_i32(x) {
        Some(MyEnum::A) => println!("Got A"),
        Some(MyEnum::B) => println!("Got B"),
        Some(MyEnum::C) => println!("Got C"),
        None            => println!("Couldn't convert {}", x),
    }
}

在您的Cargo.toml

[dependencies]
num-traits = "0.2"
num-derive = "0.2"

在更多细节NUM-派生箱 ,见电除尘器。 示例使用的测试 。



Answer 3:

std::num::FromPrimitive被标记为不稳定的 ,并且将不会被包括在锈病1.0。 作为一种变通方法,我写的enum_primitive ,其中出口宏enum_from_primitive! 一个包装了enum声明,并自动添加的实现num::FromPrimitive (从num箱 )。 例:

#[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);
}


Answer 4:

如果你确定该整数的值包括在枚举,你可以使用std::mem::transmute

这应该与使用#[repr(..)]来控制的基本类型。

完整的例子:

#[repr(i32)]
enum MyEnum {
    A = 1, B, C
}

fn main() {
    let x = MyEnum::C;
    let y = x as i32;
    let z: MyEnum = unsafe { ::std::mem::transmute(y) };

    // match the enum that came from an int
    match z {
        MyEnum::A => { println!("Found A"); }
        MyEnum::B => { println!("Found B"); }
        MyEnum::C => { println!("Found C"); }
    }
}

请注意,不像一些其他的答案,这个只需要锈病的标准库。



Answer 5:

我写了一个简单的宏,其将该数值回枚举:

macro_rules! num_to_enum {
    ($num:expr => $enm:ident<$tpe:ty>{ $($fld:ident),+ }; $err:expr) => ({
        match $num {
            $(_ if $num == $enm::$fld as $tpe => { $enm::$fld })+
            _ => $err
        }
    });
}

您可以使用它像这样:

#[repr(u8)] #[derive(Debug, PartialEq)]
enum MyEnum {
    Value1 = 1,
    Value2 = 2
}

fn main() {
    let num = 1u8;
    let enm: MyEnum = num_to_enum!(
        num => MyEnum<u8>{ Value1, Value2 };
        panic!("Cannot convert number to `MyEnum`")
    );
    println!("`enm`: {:?}", enm);
}


Answer 6:

如果您对匹配的整数是基于枚举的变体的顺序 ,你可以用扫弦生成枚举的迭代器,并采取正确的:

#[macro_use]
extern crate strum_macros; // 0.9.0
extern crate strum;        // 0.9.0

use strum::IntoEnumIterator;

#[derive(Debug, PartialEq, EnumIter)]
enum MyEnum {
    A = 1,
    B,
    C,
}

fn main() {
    let e = MyEnum::iter().nth(2);
    assert_eq!(e, Some(MyEnum::C));
}


文章来源: How do I match enum values with an integer?
标签: rust