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>; }
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.
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.
equals method uses == operator internally to check if two enum are equal. This means, You can compare Enum using both == and equals method.
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.
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With