Search code examples
rustenumsio

How can I display an enum in lowercase?


I have an enum:

pub enum BoxColour {
    Red,
    Blue,
}

I not only want to get this value as a string, but I want the value to be converted to lower case.

This works:

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(())
    }
}

When the list of colours grows, this list would need to be updated.

If I use the write! macro, it does not seem possible to manipulate the result because write! returns an instance of () instead of a String:

impl Display for BoxColour {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{:?}", self)
    }
}

This suggests that this is working through side effects and maybe we could hack the same place in memory the value is going, but even if that is possible, it probably isn't a good idea...


Solution

  • The strum crate provides a derive macro for implementing Display for an enum, and optionally lowercasing the variant names:

    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);
        }
    }
    

    You will also need the corresponding dependency on strum in your Cargo.toml:

    [dependencies]
    strum = { version = "0.21", features = ["derive"] }
    

    This should print:

    red
    blue
    light_green
    

    strum will generate code similar to the match with BoxColour::Red => "red", cases that you mentioned, but without the need to update it manually.