如何将枚举值与整数匹配?

dha*_*rdy 27 rust

我可以得到这样的枚举的整数值:

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

let x = MyEnum::C as i32;
Run Code Online (Sandbox Code Playgroud)

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

match x {
    MyEnum::A => {}
    MyEnum::B => {}
    MyEnum::C => {}
    _ => {}
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能匹配枚举值或尝试转换xMyEnum

我可以看到这样的函数对枚举很有用,但它可能不存在:

impl MyEnum {
    fn from<T>(val: &T) -> Option<MyEnum>;
}
Run Code Online (Sandbox Code Playgroud)

Ren*_*non 25

你可以派生出来FromPrimitive.使用Rust 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),
    }
}
Run Code Online (Sandbox Code Playgroud)

在你的Cargo.toml:

[dependencies]
num-traits = "0.2"
num-derive = "0.2"
Run Code Online (Sandbox Code Playgroud)

num-derive crate中的更多细节,请参见esp.样本用于测试.


win*_*ner 14

您可以利用比赛防护来编写一个等效但更笨重的结构:

match x {
    x if x == MyEnum::A as i32 => ...,
    x if x == MyEnum::B as i32 => ...,
    x if x == MyEnum::C as i32 => ...,
    _ => ...
}
Run Code Online (Sandbox Code Playgroud)

std::mem::transmute 也可以用:

let y: MyEnum = unsafe { transmute(x as i8) };
Run Code Online (Sandbox Code Playgroud)

但是这需要您知道枚举的大小,因此您可以首先转换为适当的标量,如果x不是枚举的有效值,也会产生未定义的行为.

  • 比赛后卫是个好主意。假定内存中的枚举表示是我真的不想做的事情-它很可能会与一些新的Rust版本一起破坏。首先避免使用不安全的代码是使用Rust的最大原因! (2认同)

And*_*org 12

std::num::FromPrimitive被标记为不稳定,不会包含在Rust 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);
}
Run Code Online (Sandbox Code Playgroud)


She*_*ter 9

如果您匹配的整数基于枚举变体的顺序,则可以使用strum生成枚举变体的迭代器并获取正确的迭代器:

#[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));
}
Run Code Online (Sandbox Code Playgroud)


ide*_*n42 7

如果您确定整数的值包含在枚举中,则可以使用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"); }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,与其他一些答案不同,这只需要Rust的标准库.

  • 使用不安全的函数做一些简单的事情似乎是一个非常糟糕的做法...... (4认同)
  • [这个答案](http://stackoverflow.com/a/28029667/155423) 已经提到了 `transmute` 并且只需要标准库。似乎这个答案应该只是对该答案的评论,建议使用`repr`。 (2认同)
  • @SeanBurton 编写一个本质上映射 1:1、2:2、3:3 的开关似乎也不是很好的做法。 (2认同)

She*_*ter 6

从Rust 1.34开始,我建议实现TryFrom

use std::convert::TryFrom;

impl TryFrom<i32> for MyEnum {
    type Error = ();

    fn try_from(v: i32) -> Result<Self, Self::Error> {
        match v {
            x if x == MyEnum::A as i32 => Ok(MyEnum::A),
            x if x == MyEnum::B as i32 => Ok(MyEnum::B),
            x if x == MyEnum::C as i32 => Ok(MyEnum::C),
            _ => Err(()),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用TryInto并处理可能的错误:

use std::convert::TryInto;

fn main() {
    let x = MyEnum::C as i32;

    match x.try_into() {
        Ok(MyEnum::A) => println!("a"),
        Ok(MyEnum::B) => println!("b"),
        Ok(MyEnum::C) => println!("c"),
        Err(_) => eprintln!("unknown number"),
    }
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • @NurbolAlpysbayev 它必须使用与“MyEnum”相对应的“TryInto”的实现,因为这是匹配臂中使用的值的类型(“Ok(MyEnum::A)”)。[Rust 如何从 From::&lt;&gt;::from() 推断结果类型?](/sf/ask/3131600811/); [Rust 的类型推断如何跨多个语句工作?](/sf/ask/2628008001/) (2认同)