Search code examples
classrusttraits

Define fmt::Display and fmt::Debug together


Is it possible to define fmt::Display and fmt::Debug together, i.e. such that they use the same implementation?

Assume we have the below sample code (purely for demonstration purposes):

use std::fmt;

struct MyDate {
    pub year: u16,
    pub month: u8,
    pub day: u8
}

impl PartialEq for MyDate {
    fn eq(&self, other: &Self) -> bool {
        self.year == other.year && self.month == other.month && self.day == other.day
    }
}

impl fmt::Display for MyDate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}-{:02}-{:02}", self.year, self.month, self.day)
    }
}

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

fn main() {
    let d1 = MyDate { year: 2008, month: 9, day: 10 };
    let d2 = MyDate { year: 2008, month: 9, day: 10 };

    println!("Date = {}", d1);  // requires fmt::Display
    assert_eq!(d1, d2);         // requires fmt::Debug
}

It seems that in order to print my class using println and write unit tests using assert_eq, I need to define both fmt traits. Is there a way to have 1 "print" implementation that simultaneously defines fmt::Display and fmt::Debug? For example something along the lines of impl fmt::Debug, fmt::Display for MyDate { ... } or similar?

Or is it common practice to just put #[derive(Debug)] in front of any class? Apologies if my question is naïve, as I am new to rust.


Solution

  • In most cases, Display and Debug have different output. When it makes sense to use the same formatting in both cases, the code you've written is fine. It would also be fine to #[derive(Debug)] — it's your decision to make. I think the important thing to keep in mind is that Debug should not leave anything out, and be unambiguous.

    In the case you show, the Display format shows all of the struct's fields completely accurately, so it's perfectly fine to reuse Display to implement Debug. If you had a lot of types like this, you could use a simple macro to generate Debug implementations that forward to Display.

    By the way, I would suggest using #[derive(PartialEq)] instead of the manual PartialEq implementation you show. It's completely equivalent, and avoids the dangerous failure mode of forgetting to compare a newly added field.