如何提供默认的 Debug 实现?

How do I provide a default Debug implementation?

对于您创建的大多数有助于调试的结构,#[derive(Debug)] 被认为是一种很好的做法。但是,如果您的结构包含不带 Debug 的类型(例如特征),则这是不可能的。但是如果特征在我的控制之下,我可以做些什么来让用户对所述特征的实现显示在调试消息中吗?

我可以要求实现我的特征的人也实现 Debug,但我不喜欢添加这种任意要求:

trait MyTrait: Debug { ... }

我可以为我的特质实施 Debug

trait MyTrait { ... }

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

这不允许实现覆盖 Debug - 就好像该函数不是虚拟的一样。我怎样才能使这项工作?

use std::fmt;
use std::fmt::{ Formatter, Debug };

#[derive(Debug)]
struct A {
    a: Box<Data>,
}

trait Data {}

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

#[derive(Debug)]
struct B(i32);

impl Data for B {}

fn main() {
    let a = A{ a: Box::new(B(42)) };
    println!("{:?}", a);
}

输出:

A { a: Data{ ... } }

我想要的:

A { a: B(42) }

我只想要 B 未实现 Debug 时的第一个输出。

您可以创建自己的特征方法。希望增强调试 实现 Debug 的类型可以委托:

use std::fmt;
use std::fmt::{ Formatter, Debug };

#[derive(Debug)]
struct Container(Box<Data>);

trait Data {
    fn debug_fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Data {{ ... }}")
    }
}

impl Debug for Data {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.debug_fmt(f)
    }
}

#[derive(Debug)]
struct Overrides(i32);

impl Data for Overrides {
    fn debug_fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.fmt(f)
    }
}

#[derive(Debug)]
struct Defaults(i32);
impl Data for Defaults {}

fn main() {
    let a = Container(Box::new(Overrides(42)));
    println!("{:?}", a);
    let a = Container(Box::new(Defaults(42)));
    println!("{:?}", a);
}

需要不稳定专业化功能的替代解决方案:

#![feature(specialization)]

use std::fmt;
use std::fmt::{Formatter, Debug};

struct Container<D>(Box<D>) where D: Data;

impl<D> Debug for Container<D>
    where D: Data
{
    default fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Container(Data {{ ... }})")
    }
}

impl<D> Debug for Container<D>
    where D: Data + Debug
{
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Container({:?})", self.0)
    }
}

trait Data {}

#[derive(Debug)]
struct Overrides(i32);
impl Data for Overrides {}

struct Defaults(i32);
impl Data for Defaults {}

fn main() {
    let a = Container(Box::new(Overrides(42)));
    println!("{:?}", a);
    let a = Container(Box::new(Defaults(42)));
    println!("{:?}", a);
}

请注意,这会给容器带来负担。