Reputation: 6447
For example, if I have code like:
enum Foo {
Bar,
Baz,
Bat,
Quux
}
impl Foo {
from(input: &str) -> Foo {
Foo::input
}
}
This will obviously fail because input
is not a method of Foo. I can manually type:
from(input: &str) -> Foo {
match(input) {
"Bar" => Foo::Bar,
// and so on...
}
}
but I'm not getting the automatic convenience.
It looks like Java has a string lookup function on enums for this specific purpose.
Is it possible to get this without writing my own macro or importing one from a crate?
Upvotes: 63
Views: 52229
Reputation: 26739
Same disclaimer as in other answers: "without macros" isn't possible.
Extending on the highest voted answer. As noted in this thread the combination of custom_derive
+ enum_derive
is somewhat outdated. Modern Rust doesn't need a solution based on custom_derive
anymore.
A modern alternative is strum
. Usage could look like this:
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()
}
Note: You need both strum
and strum_macros
in your Cargo.toml
.
strum
also gives some nice flexibility regarding the string representation. From the docs:
Note that the implementation of
FromStr
by default only matches on the name of the variant. There is an option to match on different case conversions through the#[strum(serialize_all = "snake_case")]
type attribute.
Upvotes: 51
Reputation: 8390
You should implement std::str::FromStr trait.
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);
}
Code-generation (aka automatic convenience) and reflections usually bear a cost. In practice, it is unlikely that you will end up with more than a few enum variants.
Run in the playground
Upvotes: 100
Reputation: 11933
Edit: The answer is no. Rust does not provide reflection and usually use #[derive]
for that kind of tasks.
You can use the crates enum_derive
and custom_derive
to do what you want.
Here is an exemple:
#[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);
}
the derive
of the custom EnumFromStr
allows you to use the parse
method to get a Foo
.
Upvotes: 29