A.B.
A.B.

Reputation: 16660

Using Formatter::debug_list to implement Debug for a two-dimensional array

I'm wondering if it's possible to get this to compile.

impl<T: fmt::Debug> fmt::Debug for Array2<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ref mut builder = f.debug_list();
        self.rows().fold(builder, |b, e| b.entry(e)).finish()
    }
}

self.rows is an iterator that yields &[T].

The error here is that Sized is not implement for [T] in the context of b.entry(e), which is bizarre because the iterator yields &[T] as mentioned before.

I'm not able to figure this out, in part because I can't make sense of the function signatures involved here.

fn entry(self, entry: &Debug) -> DebugList<'a, 'b>

Note the &Debug.

Yet the relevant documentation example is passing references &i32 to the builder.

struct Foo(Vec<i32>);

impl fmt::Debug for Foo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.0.iter().fold(fmt.debug_list(), |b, e| b.entry(e)).finish()
    }
}

With this much confusion there has to be something interesting to learn.

The desired output would be something like [[1, 2], [3, 4]].

A similar example that anyone can compile:

use std::fmt;

fn fmt<T: fmt::Debug>(vec: &Vec<T>, f: &mut fmt::Formatter) -> fmt::Result {
    let ref mut builder = f.debug_list();
    vec.chunks(4).fold(builder, |b, e| b.entry(e)).finish()
}

Upvotes: 4

Views: 345

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90832

entry() is defined thus:

pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugList<'a, 'b>;

It takes a fmt::Debug trait object. Thus when you pass it a &[T], it wants to cast it implicitly to &fmt::Debug. This, however, cannot be done, for trait objects can only be constructed of sized objects. The solution is to make a trait object of the sized slice; that is, pass something of type &&[T] which can then be implicitly converted to &fmt::Debug, containing the type &[T]. That is, b.entry(&e) instead of b.entry(e).

Your builder line is unnecessary too and actually introduces lifetime problems; you should declare it as part of the fold call for convenience.

This leaves you with this as your final result:

impl<T: fmt::Debug> fmt::Debug for Array2<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.rows().fold(&mut f.debug_list(), |b, e| b.entry(&e)).finish()
    }
}

Upvotes: 5

Related Questions