如何以小写形式显示枚举?
How can I display an enum in lowercase?
我有一个枚举:
pub enum BoxColour {
Red,
Blue,
}
我不仅要,还想把值转成小写
这个有效:
impl Display for BoxColour {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(match self {
BoxColour::Red => "red",
BoxColour::Blue => "blue",
})?;
Ok(())
}
}
当颜色列表增加时,需要更新此列表。
如果我使用 write!
宏,似乎无法操纵结果,因为 write!
returns 是 ()
的实例而不是 String
:
impl Display for BoxColour {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?}", self)
}
}
这表明这是通过副作用起作用的,也许我们可以破解内存中值所在的相同位置,但即使这是可能的,也可能不是一个好主意...
这是一种无需每次添加新颜色时手动更新 Display::fmt
的方法,方法是使用派生的 Debug
实现并将其小写:
#[derive(Debug)]
pub enum BoxColour {
Red,
Blue,
}
impl fmt::Display for BoxColour {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{}", format!("{:?}", self).to_lowercase())
}
}
请注意 write!
returns 一个 Result<(), fmt::Error>
(这是一个 fmt::Result
), 不是 原始 ()
.
但请考虑是手动更新列表更好,还是使用宏来指定。还要考虑如何将包含多个单词(例如 LightBlue
)的颜色小写:lightblue
是您想要的吗?
strum
crate 提供了一个派生宏,用于为枚举实现 Display
,并可选择小写变体名称:
use strum_macros::Display;
#[derive(Display)]
// If we don't care about inner capitals, we don't need to set `serialize_all`
// and can leave parenthesis empty.
#[strum(serialize_all = "snake_case")]
pub enum BoxColour {
Red,
Blue,
LightGreen, // example of how inner capitals are treated
}
fn main() {
for c in [BoxColour::Red, BoxColor::Blue, BoxColor::LightGreen] {
println!("{}", c);
}
}
您还需要在 Cargo.toml
:
中对 strum
的相应依赖
[dependencies]
strum = { version = "0.21", features = ["derive"] }
这应该打印:
red
blue
light_green
strum
将生成类似于 match
和您提到的 BoxColour::Red => "red",
情况的代码,但无需手动更新。
作为@Smitop 答案的扩展,通常可以使用自定义格式化程序以小写形式显示任何值,例如:
use std::fmt::{self, Write};
struct LowercaseFormatter<'a, 'b>(pub &'a mut fmt::Formatter<'b>);
impl<'a, 'b> fmt::Write for LowercaseFormatter<'a, 'b> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
for ch in s.chars() {
self.0.write_fmt(format_args!("{}", ch.to_lowercase()))?;
}
Ok(())
}
}
然后这样使用它:
#[derive(Debug)]
pub enum BoxColour {
Red,
Blue,
}
impl fmt::Display for BoxColour {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(LowercaseFormatter(formatter), "{:?}", self)
}
}
fn main() {
println!("{}", BoxColour::Red); // "red"
}
这个版本并没有为每个格式都分配一个字符串,但也不是很优化,每个字符都调用write_fmt
比较昂贵。
仅 ascii
个字符的一种替代方法是调用 write_char(ch.to_ascii_lowercase())
,但一次将一个字符写入字符串的成本也相对较高。
一个合适的解决方案是以某种方式对字符串进行分区,以便能够一次写入所有已经小写的字符,并且只写入大写字符的特殊情况。
我有一个枚举:
pub enum BoxColour {
Red,
Blue,
}
我不仅要
这个有效:
impl Display for BoxColour {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(match self {
BoxColour::Red => "red",
BoxColour::Blue => "blue",
})?;
Ok(())
}
}
当颜色列表增加时,需要更新此列表。
如果我使用 write!
宏,似乎无法操纵结果,因为 write!
returns 是 ()
的实例而不是 String
:
impl Display for BoxColour {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?}", self)
}
}
这表明这是通过副作用起作用的,也许我们可以破解内存中值所在的相同位置,但即使这是可能的,也可能不是一个好主意...
这是一种无需每次添加新颜色时手动更新 Display::fmt
的方法,方法是使用派生的 Debug
实现并将其小写:
#[derive(Debug)]
pub enum BoxColour {
Red,
Blue,
}
impl fmt::Display for BoxColour {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{}", format!("{:?}", self).to_lowercase())
}
}
请注意 write!
returns 一个 Result<(), fmt::Error>
(这是一个 fmt::Result
), 不是 原始 ()
.
但请考虑是手动更新列表更好,还是使用宏来指定。还要考虑如何将包含多个单词(例如 LightBlue
)的颜色小写:lightblue
是您想要的吗?
strum
crate 提供了一个派生宏,用于为枚举实现 Display
,并可选择小写变体名称:
use strum_macros::Display;
#[derive(Display)]
// If we don't care about inner capitals, we don't need to set `serialize_all`
// and can leave parenthesis empty.
#[strum(serialize_all = "snake_case")]
pub enum BoxColour {
Red,
Blue,
LightGreen, // example of how inner capitals are treated
}
fn main() {
for c in [BoxColour::Red, BoxColor::Blue, BoxColor::LightGreen] {
println!("{}", c);
}
}
您还需要在 Cargo.toml
:
strum
的相应依赖
[dependencies]
strum = { version = "0.21", features = ["derive"] }
这应该打印:
red
blue
light_green
strum
将生成类似于 match
和您提到的 BoxColour::Red => "red",
情况的代码,但无需手动更新。
作为@Smitop 答案的扩展,通常可以使用自定义格式化程序以小写形式显示任何值,例如:
use std::fmt::{self, Write};
struct LowercaseFormatter<'a, 'b>(pub &'a mut fmt::Formatter<'b>);
impl<'a, 'b> fmt::Write for LowercaseFormatter<'a, 'b> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
for ch in s.chars() {
self.0.write_fmt(format_args!("{}", ch.to_lowercase()))?;
}
Ok(())
}
}
然后这样使用它:
#[derive(Debug)]
pub enum BoxColour {
Red,
Blue,
}
impl fmt::Display for BoxColour {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(LowercaseFormatter(formatter), "{:?}", self)
}
}
fn main() {
println!("{}", BoxColour::Red); // "red"
}
这个版本并没有为每个格式都分配一个字符串,但也不是很优化,每个字符都调用write_fmt
比较昂贵。
仅 ascii
个字符的一种替代方法是调用 write_char(ch.to_ascii_lowercase())
,但一次将一个字符写入字符串的成本也相对较高。
一个合适的解决方案是以某种方式对字符串进行分区,以便能够一次写入所有已经小写的字符,并且只写入大写字符的特殊情况。