例如,如果我的代码如下:
enum Foo {
Bar,
Baz,
Bat,
Quux
}
impl Foo {
from(input: &str) -> Foo {
Foo::input
}
}
这显然会失败,因为input
不是Foo的方法。我可以手动输入:
from(input: &str) -> Foo {
match(input) {
"Bar" => Foo::Bar,
// and so on...
}
}
但我没有获得自动便利。
看起来Java在枚举上有string lookup function用于此特定目的。
是否可以在不编写我自己的宏或从箱子中导入宏的情况下获得这个?
答案 0 :(得分:12)
您可以使用包enum_derive
和custom_derive
来做您想做的事。
这是一个例子:
#[macro_use]
extern crate custom_derive;
#[macro_use]
extern crate enum_derive;
custom_derive! {
#[derive(Debug, EnumFromStr)]
enum Foo {
Bar,
Baz,
Bat,
Quux
}
}
fn main() {
let variable: Foo = "Bar".parse().unwrap();
println!("{:?}", variable);
}
自定义derive
的{{1}}允许您使用EnumFromStr
方法获取parse
。
答案 1 :(得分:11)
您应该实现std::str::FromStr特质。
use std::str::FromStr;
#[derive(Debug, PartialEq)]
enum Foo {
Bar,
Baz,
Bat,
Quux,
}
impl FromStr for Foo {
type Err = ();
fn from_str(input: &str) -> Result<Foo, Self::Err> {
match input {
"Bar" => Ok(Foo::Bar),
"Baz" => Ok(Foo::Baz),
"Bat" => Ok(Foo::Bat),
"Quux" => Ok(Foo::Quux),
_ => Err(()),
}
}
}
fn main() {
// Use it like this
let f = Foo::from_str("Baz").unwrap();
assert_eq!(f, Foo::Baz);
}
代码生成(又称自动便利)和反射通常要付出代价。在实践中,最终可能不会出现多个枚举变体。
答案 2 :(得分:3)
与其他答案相同的免责声明:“没有宏”是不可能的。
扩展投票最高的答案。如this thread中所述,custom_derive
+ enum_derive
的组合有些过时了。现代Rust不再需要基于custom_derive
的解决方案。
现代的替代方法是strum
。用法如下所示:
use strum_macros::EnumString;
use std::str::FromStr;
#[derive(EnumString)]
enum Foo {
Bar,
Baz,
Bat,
Quux
}
fn example_usage(input: &str) -> Foo {
Foo::from_str(input).unwrap()
}
注意:strum
中既需要strum_macros
也需要Cargo.toml
。
strum
在字符串表示方面也提供了一些很好的灵活性。来自docs:
请注意,
FromStr
的实现默认情况下仅与变体名称匹配。通过#[strum(serialize_all = "snake_case")]
type属性,可以选择不同的大小写转换。