显示
fmt::Debug
看起来并不紧凑和简洁,因此自定义输出外观通常是有利的。这是通过手动实现 fmt::Display
来完成的,它使用 {}
打印标记。实现它的方式如下
#![allow(unused)] fn main() { // Import (via `use`) the `fmt` module to make it available. use std::fmt; // Define a structure for which `fmt::Display` will be implemented. This is // a tuple struct named `Structure` that contains an `i32`. struct Structure(i32); // To use the `{}` marker, the trait `fmt::Display` must be implemented // manually for the type. impl fmt::Display for Structure { // This trait requires `fmt` with this exact signature. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Write strictly the first element into the supplied output // stream: `f`. Returns `fmt::Result` which indicates whether the // operation succeeded or failed. Note that `write!` uses syntax which // is very similar to `println!`. write!(f, "{}", self.0) } } }
fmt::Display
可能比 fmt::Debug
更简洁,但这给 std
库带来了一个问题。应该如何显示不明确的类型?例如,如果 std
库为所有 Vec<T>
实现了一种样式,那么应该是什么样式?会是以下两种样式之一吗?
Vec<path>
:/:/etc:/home/username:/bin
(以:
分割)Vec<number>
:1,2,3
(以,
分割)
不,因为没有一种理想的样式适合所有类型,而且 std
库也不打算强制规定一种样式。fmt::Display
没有为 Vec<T>
或任何其他泛型容器实现。因此,必须对这些泛型情况使用 fmt::Debug
。
但这并不是问题,因为对于任何新的*非*泛型的*容器*类型,都可以实现 fmt::Display
。
use std::fmt; // Import `fmt` // A structure holding two numbers. `Debug` will be derived so the results can // be contrasted with `Display`. #[derive(Debug)] struct MinMax(i64, i64); // Implement `Display` for `MinMax`. impl fmt::Display for MinMax { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Use `self.number` to refer to each positional data point. write!(f, "({}, {})", self.0, self.1) } } // Define a structure where the fields are nameable for comparison. #[derive(Debug)] struct Point2D { x: f64, y: f64, } // Similarly, implement `Display` for `Point2D`. impl fmt::Display for Point2D { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Customize so only `x` and `y` are denoted. write!(f, "x: {}, y: {}", self.x, self.y) } } fn main() { let minmax = MinMax(0, 14); println!("Compare structures:"); println!("Display: {}", minmax); println!("Debug: {:?}", minmax); let big_range = MinMax(-300, 300); let small_range = MinMax(-3, 3); println!("The big range is {big} and the small is {small}", small = small_range, big = big_range); let point = Point2D { x: 3.3, y: 7.2 }; println!("Compare points:"); println!("Display: {}", point); println!("Debug: {:?}", point); // Error. Both `Debug` and `Display` were implemented, but `{:b}` // requires `fmt::Binary` to be implemented. This will not work. // println!("What does Point2D look like in binary: {:b}?", point); }
因此,已经实现了 fmt::Display
,但没有实现 fmt::Binary
,因此无法使用。std::fmt
有许多这样的 特征
,每个特征都需要自己的实现。这在 std::fmt
中有更详细的说明。
活动
在检查了上面示例的输出后,以 Point2D
结构体为指导,向示例中添加一个 Complex
结构体。以相同的方式打印时,输出应为
Display: 3.3 + 7.2i
Debug: Complex { real: 3.3, imag: 7.2 }