为帮助调试而创建的大多数 struct ,最好使用#[derive(Debug)].但是,如果您的 struct 包含没有Debug的类型,例如traits,则这是不可能的.但是,如果这个特性在我的控制之下,我能做些什么,让用户对这个特性的实现显示在调试消息中吗?

我可以要求实现我的trait 的人也实现Debug,但我不想再加上这个武断的要求:

trait MyTrait: Debug { ... }

对于我的trait ,我可以实施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时得到第一个输出.

推荐答案

你可以创建自己的trait 方法.希望增强调试and实现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);
}

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

Rust相关问答推荐

属性宏修改派生宏的派生实现

捕获Rust因C++异常而产生panic

MacOS(AARCH64)上Ghidra中的二进制补丁导致进程终止

返回的future 不是`发送`

将数组转换为HashMap的更简单方法

使用Box优化可选的已知长度数组的内存分配

在我的Cargo 中,当我在建筑物中使用时,找不到我可以在产品包中使用的 crate .r我如何解决这个问题?

如果死 struct 实现了/派生了一些特征,为什么Rust会停止检测它们?

异步函数返回的future 生存期

如何使用Actix Web for Rust高效地为大文件服务

使用关联类型重写时特征的实现冲突

Rust从关联函数启动线程

如何执行数组文字的编译时串联?

如何迭代存储在 struct 中的字符串向量而不移动它们?

在 Rust 中,将可变引用传递给函数的机制是什么?

改变不实现克隆的 dioxus UseState struct

在 Rust 中为泛型 struct 编写一次特征绑定

为什么这个 Trait 无效?以及改用什么签名?

如何迭代调用可能会失败的函数?操作员?

在 Rust 中组合特征的不同方法是否等效?