实现 Vec<T> 的 fmt::Display。

12

我想为一个在我的代码中经常使用的嵌套结构实现fmt::Display

// 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
}

正如你所看到的,这是一棵非常复杂的数据树。当以单行方式呈现时,Header 中的 archive_infos 属性可能会非常长。

我想发出类似于以下内容的信息:

WhisperFile ({PATH})
  Metadata
    ...
  ArchiveInfo (0)
    ...
  ArchiveInfo (N)
    ...
但是,当我尝试显示 Vec<ArchiveInfo> 时,我得到了“未实现 Display”的错误信息。 我可以为 ArchiveInfo 实现 fmt::Display,但这并不足够,因为父容器 Vec 没有实现 fmt::Display。 如果我为 collections::vec::Vec<ArchiveInfo> 实现 fmt::Display,则会出现“该实现没有引用此 crate 中定义的任何类型;仅在当前 crate 中定义的 trait 可以为任意类型实现”。

我尝试迭代 Vec 并调用 write!(),但我无法弄清控制流应该是什么样子的。 我认为 write!() 需要是函数的返回值,但是多次调用会导致问题。

我该如何漂亮地打印我的结构体的 Vec?

1个回答

24
正如这个错误所述,您不能为您不拥有的类型实现trait:

impl没有引用此crate中定义的任何类型; 只能为当前crate中定义的trait实现任意类型

但是,您可以为包装类型实现Display。 您缺少的部分是使用try!宏或try运算符?
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);
}

2
实现部分没有引用在这个 crate 中定义的任何类型,但是,在这种情况下,措辞仍然令人困惑;毕竟 Vec<ArchiveInfo> 确实引用了在这个 crate 中定义的一个类型。 - Matthieu M.
我不熟悉 &self.0 这一部分。看起来你的结构是基于位置的,因此我想它执行了一个基于位置的查找? - xrl
@xrl 哦,是的,抱歉。您可以拥有一个tuple struct,其中结构成员是匿名的,但可按位置使用(.0.1等)。当它是单个成员时,它被称为newtype,这是一种很好的方式,可以在现有类型周围包装自己的语义。 - Shepmaster
这里有一个不相关的问题,struct Foo(Vec<u8>); 这个括号的语法是什么? - Sajuuk
@Sajuuk https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types - Shepmaster
这里是精确的“孤儿规则”:https://doc.rust-lang.org/beta/reference/items/implementations.html#orphan-rules - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接