有没有办法编写一个函数,可以输出到 std::io::Write 或 std::fmt::Formatter?

10

我想编写一个函数来生成一些文本,就像这样:

fn produce_stuff(/* ??? */) -> Result<()> {
    write!(...);
    write!(...);
    write!(...);
    ...
}

我希望能够在两个上下文中使用这个函数:

  1. 将其用于输出到IO writer - 类似于 produce_text(io.stdout())
  2. 将其用作实现Display的辅助函数 - 类似于以下内容:
struct Foo { ... }
impl Display for Foo {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        ...
        produce_text(f);
        ...
    }
}

似乎每个用例都需要 produce_text 的不同签名。对于 #1,函数需要接受实现了 std::io::Write 的内容,而对于 #2,则需要接受一个 std::fmt::Formatter

我想我可以将其编写为宏而不是函数(类似于 write! 是在两种上下文中均可使用的宏),但某种程度上感觉使用宏有些不妥。


这是Display的作用。 - Stargateur
1个回答

7

您只需要实现Display接口即可。

当您的Foo实现了Display接口后,您就可以将其与任何实现了Write接口的对象一起使用,包括io::Stdout

use std::{
    io::{self, Write},
    fmt,
};

struct Foo {
    field: u16,
}
impl fmt::Display for Foo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Foo({})", self.field)
    }
}

fn main() {
    write!(io::stdout(), "{}", Foo{field: 3}).unwrap();
}

你不必自己编写宏,只需使用write!。这应该不会感觉不对,这是正常的方式。
"{}"参数相关的运行时成本为零:它在编译时(在编译器内置中)被解析,这使得write!(w,“{}”,displayable)调用高效。 playground

在这种情况下,我的文本生成函数并没有与任何特定类型相关联,因此选择实现Display的类型并不明显。我想我可以只定义一个空的虚拟结构体,并在其上实现Display。 - Will
@Will 通常有语义关联,可以定义一个足够有用的结构体来实现 Display,并在其他 Display 中重复使用它。它不必拥有自己的数据。我在 Termimad 中就是这样做的:https://github.com/Canop/termimad/blob/master/src/displayable_line.rs - Denys Séguret

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