将枚举作为字符串

Isk*_*rak 24 rust

我有一个有许多价值观的枚举

enum Foo {
  Bar = 0x00,
  Baz = 0x01,
  Qux = 0x02,
  ...
  Quux = 0xFF
}
Run Code Online (Sandbox Code Playgroud)

有时我想将其中一个值的名称写入流中.我可以得出Debug

writer.write(format!("I am {:?}", Foo::Quux).as_bytes())
Run Code Online (Sandbox Code Playgroud)

这将输出例如I am Quux.那很好,除了那个

  • 我想为面向用户的输出执行此操作,因此Debug不合适
  • 将枚举作为字符串(而不是直接写入流)非常有用,因为我可以将其长度合并到我想要做的一些不稳定的格式计算中.

实现这一目标的最佳方法是什么?

Vla*_*eev 38

可能最简单的方法是Display通过调用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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以to_string()用来获得一个String表示:

let s: String = Foo::Quux.to_string();
Run Code Online (Sandbox Code Playgroud)

如果您要打印许多枚举,可以编写一个简单的宏来Display为每个枚举生成上述实现.

不幸的是,在Rust中,反射编程有点困难.例如,没有标准的方法来获取类似C的枚举的所有变体的列表.几乎总是你必须使用自定义编写的宏来抽象样板(或者在crates.io上找到一些东西).如果有人写一个RFC并且它会被接受,将来可能会改变.

  • 如果你使用std :: fmt :: {self,Debug,Display}`,只需调用`Debug :: fmt(self,f)`就更简单了. (7认同)
  • @DavidC.Bishop [不,它没有。](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d6aef09223299d9692276c8e43677c5d)当然,如果你对结果字符串调用 Debug ,它会的。 (2认同)

She*_*ter 9

由于枚举变量的名称是固定的,你并不需要分配一个String,一个&'static str就够了。宏可以删除样板:

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");
}
Run Code Online (Sandbox Code Playgroud)

更好的是,您可以使用strum_macros这样的板条箱派生这些。

在strum 0.10中,您可以使用AsStaticRef/ AsStaticStr来执行完全相同的代码:

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");
}
Run Code Online (Sandbox Code Playgroud)

在strum 0.9中,字符串切片的生存期在这种情况下不是'static

#[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");
}
Run Code Online (Sandbox Code Playgroud)