12

I want to implement the fmt::Display for a nested struct commonly used in my code.

// The root structure
pub struct WhisperFile<'a> {
    pub path: &'a str,
    pub handle: RefCell<File>,
    pub header: Header
}

pub struct Header{
    pub metadata: metadata::Metadata,
    pub archive_infos: Vec<archive_info::ArchiveInfo>
}

pub struct Metadata {
   // SNIP
}

pub struct ArchiveInfo {
   // SNIP
}

As you can see, this is a non-trivial tree of data. The archive_infos property on Header can be quite long when presented as one line.

I would like to emit something along the lines of

WhisperFile ({PATH})
  Metadata
    ...
  ArchiveInfo (0)
    ...
  ArchiveInfo (N)
    ...

But when I try to display Vec<ArchiveInfo> I get that Display is not implemented. I can implement fmt::Display for ArchiveInfo but that's not enough since fmt::Display is not implemented for the parent container Vec. If I implement fmt::Display for collections::vec::Vec<ArchiveInfo> I get the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types.

I have tried iterating over the vec and calling write!() but I couldn't figure out what the control flow should look like. I think write!() needs to be return value of the function but that breaks down with multiple calls.

How can I pretty print a Vec of my structures?

xrl
  • 2,155
  • 5
  • 26
  • 40

1 Answers1

24

As this error states, you cannot implement a trait for a type you don't own:

the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types

However, you can implement Display for your wrapper type. The piece you are missing is to use the try! macro or the try operator ?:

use std::fmt;

struct Foo(Vec<u8>);

impl fmt::Display for Foo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Values:\n")?;
        for v in &self.0 {
            write!(f, "\t{}", v)?;
        }
        Ok(())
    }
}

fn main() {
    let f = Foo(vec![42]);
    println!("{}", f);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    *the impl does not reference any types defined in this crate* => still, in this case, the wording is confusing; `Vec` does reference a type defined in this crate after all. – Matthieu M. Jun 04 '15 at 06:23
  • I am not familiar with the `&self.0` bit. Looks like your structure is positional so I suppose it does a positional lookup? – xrl Jun 04 '15 at 18:28
  • @xrl oh yes, sorry. You can have a `tuple struct` where the struct members are anonymous, but available positionally (`.0`, `.1`, ...). When it is a single member, it's called a *newtype*, which is a nice way of wrapping your own semantics around an existing type. – Shepmaster Jun 04 '15 at 18:32
  • An irrelevant question here, struct Foo(Vec); what is this syntax (of parenthesis)? – Sajuuk Jul 30 '19 at 06:23
  • @Sajuuk https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types – Shepmaster Jul 30 '19 at 12:23