rust で数値からenumに変換する
rustのenumを定数を列挙するためだけに使いたいということもありますね?(ないですか?)
そういう時、数値からenumに変換したいということがありますね?(ないですか?)
rustのenumはこんなふうに定義します。 rustのenumはだいぶ高機能なのでいろんなことができますが、今回は定数の列挙に使いたいという想定ですね。
enum TrafficLight{ Blue, Yellow, Red, }
このように定義するとデフォルトで0から数値がふられるので enum から数値に 変換することはできます。
fn main() { println!("{:?} = {}", TrafficLight::Blue, TrafficLight::Blue as i32); println!("{:?} = {}", TrafficLight::Yellow, TrafficLight::Yellow as i32); println!("{:?} = {}", TrafficLight::Red, TrafficLight::Red as i32); }
結果
$ cargo run Blue = 0 Yellow = 1 Red = 2
こうなります。
逆はできません。
$ cargo build src/main.rs:12:32: 12:49 error: non-scalar cast: `i32` as `TrafficLight` src/main.rs:12 let light : TrafficLight = 0 as TrafficLight; ^~~~~~~~~~~~~~~~~ error: aborting due to previous error Could not compile `light`. To learn more, run the command again with --verbose.
こうなります。
調べてみると以下がでてきますね。
書いてある通りに std::num::FromPrimitive
は削除されてしまいましたが、今は http://doc.rust-lang.org/num/num/index.html に同様な機能を持つものが入っています。
crateに頼ることになるのは遺憾ですが公式が提供してる(?)ものなのでまぁいいとしましょう。
これを使って FromPrimitive
という trait を実装すると
from_i64(n: i64) from_u64(n: u64) from_isize(n: isize) from_i8(n: i8) from_i16(n: i16) from_i32(n: i32) from_usize(n: usize) from_u8(n: u8) from_u16(n: u16) from_u32(n: u32) from_f32(n: f32) from_f64(n: f64)
これらが使えるようになるので、基本の数値型ならどれからでも変換できるようになります。
実装する必要があるのは、 from_i64
と from_u64
の2つです。
以下使い方
Cargo.toml に依存を追加しましょう
[dependencies] num = "*"
で実装してきます
extern crate num; use num::traits::FromPrimitive; impl FromPrimitive for TrafficLight { fn from_i64(n: i64) -> Option<TrafficLight> { match n { 0 => Some(TrafficLight::Blue), 1 => Some(TrafficLight::Yellow), 2 => Some(TrafficLight::Red), _ => None, } } fn from_u64(n: u64) -> Option<TrafficLight> { match n { 0 => Some(TrafficLight::Blue), 1 => Some(TrafficLight::Yellow), 2 => Some(TrafficLight::Red), _ => None, } } }
こうです。
このmatchあたりがめんどくさいのでなんとかしたいですね。いい方法があるといいんですが。
ここに数値を書かないといけないとなると網羅してるかもよくわからないし変更や追加に弱いしこれはなんとかしたいです。
(これのいい方法が知りたくてこんな記事をだらだら書いてると言っても過言ではありません。誰か教えてください。)
let blue = TrafficLight::from_i64(0 as i64).unwrap(); let yellow = TrafficLight::from_u8(1 as u8).unwrap(); let red = TrafficLight::from_usize(2 as usize).unwrap(); println!("{:?}", blue); println!("{:?}", yellow); println!("{:?}", red);
結果
$ cargo run Blue Yellow Red
できましたね