我试图根据参数实现不同的Display格式。比如print_json()和print_pretty()。当然,我可以将其实现为返回字符串print_json(&self)->String的函数,但我想知道是否可以让print_json(&self,f: &mut Formatter<'_>) -> std::fmt::Result和print_pretty(&self,f: &mut Formatter<'_>) -> std::fmt::Result代替。然后,我可以根据用例调用这些函数中的任何一个。但是如何直接获得Formatter的实例呢?理想情况下,我想做这样的事情
let mut string = String::new();
my_object.print_pretty(&mut string);
return string;发布于 2021-06-05 20:01:38
但是如何直接获得
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;。或者,你可以有两个不同的特征--我刚刚发现,拥有一个通用的特性可以减少代码的重复。
作为实现示例,这里我定义了std::time::Duration的自定义格式。它看起来就像一个Debug或Display实现,只不过它需要一个额外的格式-选项参数(它会忽略这个参数,因为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,以转发到您的自定义格式特征(或者,如果您只想自定义一种类型,那么只需要该对象上的方法)。
https://stackoverflow.com/questions/67852867
复制相似问题