How do I get an enum as a string?

I have an enum with many values and I'd like to write the name of one of its values to a stream:

enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
// ...
Quux = 0xFF,
}

I can derive Debug and do

writer.write(format!("I am {:?}", Foo::Quux).as_bytes())

which will output e.g. I am Quux. That's fine, except that

  • I want to do this for user-facing output, so Debug isn't appropriate
  • It would be very helpful to get the enum as a string (rather than writing directly to a stream), because then I can incorporate its length into some wonky formatting calculations I want to do.
71880 次浏览

Probably the easiest way would be to implement Display by calling into Debug:

impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
// or, alternatively:
// fmt::Debug::fmt(self, f)
}
}

Then you can use to_string() to get a String representation:

let s: String = Foo::Quux.to_string();

If you have many enums which you want to print, you can write a trivial macro to generate the above implementation of Display for each of them.

Unfortunately, in Rust reflective programming is somewhat difficult. There is no standard way, for example, to get a list of all variants of a C-like enum. Almost always you have to abstract the boilerplate with custom-written macros (or finding something on crates.io). Maybe this will change in future if someone would write an RFC and it would get accepted.

Since the names of enum variants are fixed, you don't need to allocate a String, a &'static str will suffice. A macro can remove the boilerplate:

macro_rules! enum_str {
(enum $name:ident {
$($variant:ident = $val:expr),*,
}) => {
enum $name {
$($variant = $val),*
}


impl $name {
fn name(&self) -> &'static str {
match self {
$($name::$variant => stringify!($variant)),*
}
}
}
};
}


enum_str! {
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
//...
Quux = 0xFF,
}
}


fn main() {
assert_eq!(Foo::Baz.name(), "Baz");
}

Even better, you can derive these with a crate like strum_macros.

In strum 0.10, you can use AsStaticRef / AsStaticStr to do the exact same code:

extern crate strum; // 0.10.0
#[macro_use]
extern crate strum_macros; // 0.10.0


use strum::AsStaticRef;


#[derive(AsStaticStr)]
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
//...
Quux = 0xFF,
}


fn main() {
assert_eq!(Foo::Baz.as_static(), "Baz");
}

In strum 0.9, the string slice's lifetime is not 'static in this case:

#[macro_use]
extern crate strum_macros; // 0.9.0


#[derive(AsRefStr)]
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
//...
Quux = 0xFF,
}


fn main() {
assert_eq!(Foo::Baz.as_ref(), "Baz");
}