我有一个包含很多值的枚举
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
...
Quux = 0xFF
}
有时我想将其中一个值的名称写入流中。我可以派生Debug
并做
writer.write(format!("I am {:?}", Foo::Quux).as_bytes())
将输出例如I am Quux
。那很好,除了
实现这一目标的最佳途径是什么?
答案 0 :(得分:29)
最简单的方法可能是通过调用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)
}
}
然后,您可以使用to_string()
获取String
代表:
let s: String = Foo::Quux.to_string();
如果您要打印许多枚举,可以编写一个简单的宏来为每个枚举生成Display
的上述实现。
不幸的是,在Rust中,反射编程有点困难。例如,没有标准的方法来获取类似C的枚举的所有变体的列表。几乎总是你必须使用自定义编写的宏来抽象样板(或者在crates.io上找到一些东西)。如果有人写一个RFC并且它会被接受,也许这将在未来发生变化。
答案 1 :(得分:7)
由于枚举变体的名称已修复,因此您无需分配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");
}
更好的是,你可以使用像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");
}
在strum 0.9中,字符串切片的生命周期为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");
}