52

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?

bright-star
  • 6,016
  • 6
  • 42
  • 81
  • 1
    What if instead of `"Bar"` you need `"Foo::Bar"` or `"my_module::Foo::Bar"` or `"bar"`? That helps explain why there's no pre-made way to do this. There's nothing in the standard library, beyond that you would just be asking for a library / tool recommendation. – Shepmaster Aug 22 '16 at 01:32
  • I don't think your edit on my answer is necessary: you asked for automatic convenience, which you get with the crates I mentioned and you don't have to write you own macro, because the crates already provide the macro. – antoyo Aug 22 '16 at 16:34

3 Answers3

83

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

Pandemonium
  • 7,724
  • 3
  • 32
  • 51
42

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.

bluenote10
  • 23,414
  • 14
  • 122
  • 178
28

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.

antoyo
  • 11,097
  • 7
  • 51
  • 82
  • If it is not what you want, please edit your question, because, as I said [here](http://stackoverflow.com/questions/39070244/can-i-convert-a-string-to-enum-without-macros-in-rust/39070533#comment-65517006), I don't see why it does not answer your question. – antoyo Aug 22 '16 at 21:47
  • 1
    Great answer, but not to this question. I was also looking for an answer. – Flavius May 25 '19 at 19:00
  • I thought the OP explicitly asked "without macros". – vasilakisfil Oct 09 '19 at 07:56
  • I think the answer is that it is not possible without a macro, although I would have this double-checked by a more experienced Rustacean before I try editing the answer to make it clearer. – iago-lito Apr 07 '20 at 10:36
  • Make sure to check out the other answer about macros: https://stackoverflow.com/a/62711168/2650622 The crates linked here seem unmaintained – Agost Biro Jun 06 '22 at 16:00