Reputation: 3265
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.
Upvotes: 7
Views: 4133
Reputation: 8052
Performance consideration: in your Debug
implementation, you are calling the Display
implementation of the same object:
impl fmt::Debug for MyDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self) // call method from Display
}
}
However, when doing this, Debug::fmt()
calls write!
twice – and this is not a cheap operation.
A better implementation would be calling directly the method from the Display
trait:
impl fmt::Debug for MyDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
Now write!
is called only once.
Or is it common practice to just put
#[derive(Debug)]
in front of any class?
Yes, it's very common. Implementing your custom Debug
is interesting only if you want a custom output of the fields in your struct.
Upvotes: 0
Reputation: 43782
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.
Upvotes: 5