How can I implement fmt::Display for Enum

I've the below enum

enum Day {
    Monday, Tuesday, Wednesday, Thursday, Friday
}

When I tried doing:

println!("z: {}", Day::Saturday);

I got the below:

    error[E0277]: `Day` doesn't implement `std::fmt::Display`                                                                                                                            
      --> bin/src/main.rs:11:31                                                                                                                                                          
       |                                                                                                                                                                                 
    11 |             println!("z: {}", Day::Saturday);                                                                                                                                   
       |                               ^^^^^^^^^^^^^ `Day` cannot be formatted with the default formatter                                                                                
       |                                                                                                                                                                                 
       = help: the trait `std::fmt::Display` is not implemented for `Day`                                                                                                                
       = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead                                                                                       
       = note: required by `std::fmt::Display::fmt`  

So, i changed the code to be:

println!("z: {:?}", Day::Saturday);

And getting now the below:

error[E0277]: `Day` doesn't implement `std::fmt::Debug`                                                                                                                              
  --> bin/src/main.rs:11:33                                                                                                                                                          
   |                                                                                                                                                                                 
11 |             println!("z: {:?}", Day::Saturday);                                                                                                                                 
   |                                 ^^^^^^^^^^^^^ `Day` cannot be formatted using `{:?}`                                                                                            
   |                                                                                                                                                                                 
   = help: the trait `std::fmt::Debug` is not implemented for `Day`                                                                                                                  
   = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug`                                                                                                            
   = note: required by `std::fmt::Debug::fmt`

This had been resolved by adding #[derive(Debug)] as:

#[derive(Debug)]
enum Day {
    Saturday, Sunday ,Monday, Tuesday, Wednesday, Thursday, Friday
}

I tried to use Debug and Release traits implementation instead of using #[derive(Debug)], so I wrote the below:

use std::fmt;

impl fmt::Debug for Day {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

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

And tried it with the below code:

println!("z: {:?}", Day::Saturday);

But got the below error:

thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Abort trap: 6
5 Likes

This usually indicates a recursion issue. Indeed, in this implementation

impl fmt::Debug for Day {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

you are calling <Day as Debug>::fmt recursively.

2 Likes

What #[derive(Debug)] does is automatically insert this code into your program:

impl fmt::Debug for Day {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Day::Monday => write!(f, "Monday"),
            Day::Tuesday => write!(f, "Tuesday"),
            Day::Wednesday => write!(f, "Wednesday"),
            Day::Thursday => write!(f, "Thursday"),
            Day::Friday => write!(f, "Friday"),
        }
    }
}

What write!(f, "{:?}", x) does is call your type's Debug::fmt method. So you've replaced #[derive(Debug)] with your on manual implementation of Debug where Debug::fmt calls Debug::fmt, which calls Debug::fmt, which calls Debug::fmt, and so on in an infinite loop which crashes the stack.

If you want an implementation of Display which prints the same thing as Debug then you can leave #[derive(Debug)] on your type and just use the impl of Display which you've shown in your code - the one where Display::fmt just calls Debug::fmt.

9 Likes

Thanks a lot, so what is the different between Debug and Display?

1 Like

write!(f, "{:?}", x) uses Debug
write!(f, "{}", x) uses Display

They work the same way but Debug is intended to be implemented by almost every type and only used for debugging purposes. Display is for types that have a proper string representation.

For example: The string "foo" would be printed by Debug as "foo" and printed by Display as just foo (without the quotes). A type like HashMap implements Debug but doesn't implement Display because there's more than one way you might want to "display" a HashMap. Number types like u32 implement both and print the same thing for both because people have a standard way of writing numbers.

Basically: Debug prints something that looks like code. Display prints something that doesn't look like code - something you'd happily show your users in a message.

8 Likes

Appreciated :smiling_face_with_three_hearts:

1 Like

By the way, you might like strum

3 Likes

That's not quite true. The "standard" way of writing numbers depends on the locale. In an internationalized application, using Display for numbers is not possible (e.g. 1.200 would mean 1200 in some countries).

4 Likes

@Riateche Yeah, I know. But I figured what I said is close enough to true and it helps convey my point.

1 Like