Rust 直接调用 fmt 函数

4

我想根据不同的参数实现不同的显示格式,例如print_json()print_pretty()。 我当然可以将其实现为返回字符串的函数print_json(&self)->String,但我想知道是否有可能有print_json(&self,f: &mut Formatter<'_>) -> std::fmt::Resultprint_pretty(&self,f: &mut Formatter<'_>) -> std::fmt::Result这样的函数,那我就可以根据用例调用其中任何一个函数。 但是,如何直接获取Formatter的实例? 理想情况下,我想要做的是:

let mut string = String::new();
my_object.print_pretty(&mut string);
return string;
1个回答

6

但是我如何直接获取Formatter实例?

据我所知,获得Formatter的唯一方法是通过实现Display或其他格式化特性之一来接收它。

我已经根据这个核心特性实现了自己的方案,以添加更多的格式化选项:

/// Objects for which alternate textual representations can be generated.
/// These are analogous to [`Display`] and [`Debug`], but have additional options.
pub trait CustomFormat<F: Copy> {
    /// Wrap this value so that when formatted with [`Debug`] or [`Display`] it uses
    /// the given custom format instead.
    fn custom_format(&self, format_type: F) -> CustomFormatWrapper<'_, F, Self> {
        CustomFormatWrapper(format_type, self)
    }

    /// Implement this to provide custom formatting for this type.
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>, format_type: F) -> fmt::Result;
}

希望支持额外格式类型的类型需要实现 CustomFormat<F>,其中F是特定的格式类型或格式选项;在您的用例中,它们可以是struct Json;struct Pretty;。或者,您可以有两个不同的 traits —— 我发现一个通用 trait 可以减少代码重复。

作为一个实现示例,在这里我定义了一个 std::time::Duration 的自定义格式。它看起来就像一个 DebugDisplay 实现,只是多了一个格式选项参数(它会被忽略,因为 StatusText 并没有任何额外的选项):

impl CustomFormat<StatusText> for Duration {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: StatusText) -> fmt::Result {
        write!(fmt, "{:5.2?} ms", (self.as_micros() as f32) / 1000.0)
    }
}

你使用这些工具的代码示例如下:

let mut string = String::new();
write!(string, "{}", my_object.custom_format(Pretty)).unwrap();
return string;
"{}" 格式字符串不再控制格式;它只是一个占位符,通过实现 Display(以及 Debug)来调用自定义格式化的 CustomFormatWrapper 来触发格式化机制:
pub struct CustomFormatWrapper<'a, F: Copy, T: CustomFormat<F> + ?Sized>(F, &'a T);

impl<'a, F: Copy, T: CustomFormat<F>> Debug for CustomFormatWrapper<'a, F, T> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        <T as CustomFormat<F>>::fmt(self.1, fmt, self.0)
    }
}

impl<'a, F: Copy, T: CustomFormat<F>> Display for CustomFormatWrapper<'a, F, T> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        <T as CustomFormat<F>>::fmt(self.1, fmt, self.0)
    }
}

这可能是你的目的过度设计的解决方案。所需的关键元素是包含对要格式化值的引用的包装类型,以及它具有一些标准格式化特性(例如Display),以转发到你自定义的格式化特性(或者如果你只想自定义格式化一种类型,则只需要该对象上的方法)。 完整源代码链接

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