如何确定可以格式化的类型的打印宽度?

Dan*_*elV 2 formatting rust

如果一个类型实现Debug,我如何确定将从 a 打印的内容的宽度println!("{:?}", ...)

fn width<T: std::fmt::Debug>(to_print_later: &T) -> usize {
    // what goes here?
}
Run Code Online (Sandbox Code Playgroud)

最好不要在堆上实际分配任何东西,也绝对不要实际打印任何东西。

She*_*ter 5

如果不实际执行格式化,则无法执行此操作。默认情况下,格式化是惰性的,并且格式化特征没有允许查询大小的方法。

此外,类型的实现Debug::fmt可能会或可能不分配,因此它不可能说没有发生分配。

最简单的方法是创建一个字符串并返回字符串的长度:

fn width(to_print_later: &impl std::fmt::Debug) -> usize {
    format!("{:?}", to_print_later).len()
}
Run Code Online (Sandbox Code Playgroud)

如果你想避免自己的分配,你可以将自己的实现者fmt::Write和格式写入其中,只计算长度:

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

fn width(to_print_later: &impl fmt::Debug) -> usize {
    let mut c = CountingWriter::default();
    write!(&mut c, "{:?}", to_print_later).expect("Exceeded the usize");
    c.0
}

#[derive(Debug, Default)]
struct CountingWriter(usize);

impl fmt::Write for CountingWriter {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.0 = usize::checked_add(self.0, s.len()).ok_or(fmt::Error)?;
        Ok(())
    }
}
Run Code Online (Sandbox Code Playgroud)

这不是一个确定的性能胜利,因为 的实现可能Debug::fmt是重量级的部分,而不是分配。像往常一样,配置文件以了解最适合您的情况。


请注意,我Debug在此答案中使用了它,但它也适用于其他特征,例如DisplayLowerHex