Closed8
[Rust] Enum と文字列の変換
ピン留めされたアイテム
Rust で文字列と Enum の相互変換をやりたい。コマンドラインのオプションを解析するときに、
cmd --arg arg
で渡された arg
を Enum に変換したい。しかも、失敗した時には変換候補も表示したい。
変換には、いくつかの Trait が用意されている。
- Enum から文字列への変換 Display in std::fmt
- 文字列から Enum への変換
とりあえず、こんな感じで実装はできるが、毎回これを実装するのはさすがに面倒。また、variants()
に追加忘れたとしてもコンパイラは何も言ってくれない。
pub enum Foo {
A,
B,
}
impl Foo {
pub fn variants() -> impl Iterator<Item = Foo> {
array::IntoIter::new([Self::A, Self::B])
}
}
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Foo::A => write!(f, "a"),
Foo::B => write!(f, "b"),
}
}
}
impl FromStr for Foo {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::variants()
.find(|x| x.to_string() == s)
.ok_or_else(|| format!("Unknown option: `{}`", s))
}
}
static な enum に
- メンバーの個数を取得する static メソッド
- Iterator を返すメソッド
を追加する crate
thiserror のように使える crate があると便利かも?
use strenum::StringEnum;
#[derive(StringEnum, Debug)]
pub enum Vegetable {
#[str("Potato")]
Potato,
#[str("Broccori")]
Broccori,
#[str("Carrot")]
Carrot,
}
フィールドを持つ enum もできないだろうか?
use strenum::StringEnum;
#[derive(StringEnum, Debug)]
pub enum ConnectionState {
#[str("initializing")]
Initializing,
#[str("Connected({0})")]
Connected(i32),
#[str("Disconnected")]
Disconnected,
}
最短マッチで文字列を読んで、FromStr を実装しているフィールドなら出来そう? すでにありそうだな。
strum 使ってみた。
use strum::IntoEnumIterator;
#[derive(
Debug,
PartialEq,
Clone,
Copy,
strum_macros::EnumString,
strum_macros::Display,
strum_macros::IntoStaticStr,
strum_macros::EnumIter,
)]
pub enum Color {
#[strum(serialize = "red")]
Red,
#[strum(serialize = "blue")]
Blue,
}
これだけで、Color::iter()
や Into<&'static str>
が実装される。
let color_option_values: Vec<&'static str> = Color::iter().map(|o| o.into()).collect();
このスクラップは2021/10/17にクローズされました