如何提供默认的Debug实现?

时间:2017-02-19 23:55:55

标签: rust traits virtual-functions

对于您创建的大多数结构来说,#[derive(Debug)]被认为是一种良好的做法,有助于调试。但是,如果您的struct包含没有Debug的类型(如traits),则无法执行此操作。但是,如果这个特性在我的控制之下,那么我能做些什么才能让用户能够做到这一点。所述特征的实现显示在调试消息中?

我可以要求实施我的特质的人也实施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时的第一个输出。

1 个答案:

答案 0 :(得分:5)

您可以创建自己的特质方法。希望增强调试实现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);
}

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