一起定义 fmt::Display 和 fmt::Debug

Define fmt::Display and fmt::Debug together

是否可以一起定义 fmt::Displayfmt::Debug,即它们使用相同的实现?

假设我们有以下示例代码(仅用于演示目的):

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
}

似乎为了使用 println 打印我的 class 并使用 assert_eq 编写单元测试,我需要定义两个 fmt 特征。有没有办法让 1 个“打印”实现同时定义 fmt::Displayfmt::Debug?例如,类似于 impl fmt::Debug, fmt::Display for MyDate { ... } 或类似的东西?

或者只是将 #[derive(Debug)] 放在任何 class 前面是常见的做法吗?如果我的问题很天真,我很抱歉,因为我是生锈的新手。

在大多数情况下,DisplayDebug 有不同的输出。如果在两种情况下都使用相同的格式是有意义的,那么您编写的代码就可以了。 #[derive(Debug)] 也可以——这是你的决定。我认为要记住的重要一点是 Debug 应该 不遗漏任何东西,并且要明确。

在您显示的情况下,Display 格式完全准确地显示了结构的所有字段,因此重用 Display 来实现 Debug 完全没问题。如果你有很多这样的类型,你可以使用一个简单的宏来生成转发到 Display.

Debug 实现

顺便说一句,我建议使用 #[derive(PartialEq)] 而不是您展示的手动 PartialEq 实现。它是完全等价的,并且避免了忘记比较新添加字段的危险失败模式。