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.
CodePudding user response:
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.