Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I match enum values with an integer?

Tags:

rust

I can get an integer value of an enums like this:

enum MyEnum {     A = 1,     B,     C, }  let x = MyEnum::C as i32; 

but I can't seem to do this:

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

How can I either match against the values of the enum or try to convert x back to a MyEnum?

I can see a function like this being useful for enums, but it probably doesn't exist:

impl MyEnum {     fn from<T>(val: &T) -> Option<MyEnum>; } 
like image 773
dhardy Avatar asked Jan 19 '15 16:01

dhardy


People also ask

Can we compare enum with int?

Cast Int To Enum may be of some help. Go with the 2nd option. The 1st one can cause an exception if the integer is out of the defined range in your Enumeration. In current example I compare to 'magic number' but in real application I am getting data from integer field from DB.

How do you find the enum value of an integer?

To get the value of enum we can simply typecast it to its type. In the first example, the default type is int so we have to typecast it to int. Also, we can get the string value of that enum by using the ToString() method as below.

Can == be used on enum?

equals method uses == operator internally to check if two enum are equal. This means, You can compare Enum using both == and equals method.


2 Answers

You can derive FromPrimitive. Using Rust 2018 simplified imports syntax:

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),     } } 

In your Cargo.toml:

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

More details in num-derive crate, see esp. sample uses in tests.

like image 139
Renato Zannon Avatar answered Sep 25 '22 22:09

Renato Zannon


Since Rust 1.34, I recommend implementing 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(()),         }     } } 

Then you can use TryInto and handle the possible error:

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"),     } } 

If you have a great number of variants, a macro can be used to create a parallel implementation of TryFrom automatically based on the definition of the enum:

macro_rules! back_to_enum {     ($(#[$meta:meta])* $vis:vis enum $name:ident {         $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*     }) => {         $(#[$meta])*         $vis enum $name {             $($(#[$vmeta])* $vname $(= $val)?,)*         }          impl std::convert::TryFrom<i32> for $name {             type Error = ();              fn try_from(v: i32) -> Result<Self, Self::Error> {                 match v {                     $(x if x == $name::$vname as i32 => Ok($name::$vname),)*                     _ => Err(()),                 }             }         }     } }  back_to_enum! {     enum MyEnum {         A = 1,         B,         C,     } } 

See also:

  • How to ensure every enum variant can be returned from a specific function at compile time?
  • Generating documentation in macros
like image 40
Shepmaster Avatar answered Sep 22 '22 22:09

Shepmaster