显示 Display
fmt::Debug
的输出往往不够简洁清晰,因此自定义输出外观通常更有优势。 这可以通过手动实现 fmt::Display
来完成, 它使用 {}
打印标记。实现方式如下:
#![allow(unused)] fn main() { // 通过 `use` 导入 `fmt` 模块使其可用。 use std::fmt; // 定义一个结构体,我们将为其实现 `fmt::Display`。 // 这是一个名为 `Structure` 的元组结构体,包含一个 `i32`。 struct Structure(i32); // 要使用 `{}` 标记,必须为该类型手动实现 `fmt::Display` trait。 impl fmt::Display for Structure { // 这个 trait 要求 `fmt` 方法具有确切的签名。 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // 将第一个元素严格写入提供的输出流 `f`。 // 返回 `fmt::Result`,表示操作是否成功。 // 注意 `write!` 的语法与 `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; // 导入 `fmt` // 定义一个包含两个数字的结构体。派生 `Debug` 特性, // 以便与 `Display` 的结果进行对比。 #[derive(Debug)] struct MinMax(i64, i64); // 为 `MinMax` 实现 `Display` 特性。 impl fmt::Display for MinMax { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // 使用 `self.number` 引用每个位置的数据点。 write!(f, "({}, {})", self.0, self.1) } } // 定义一个结构体,其字段可命名以便比较。 #[derive(Debug)] struct Point2D { x: f64, y: f64, } // 同样,为 `Point2D` 实现 `Display` 特性。 impl fmt::Display for Point2D { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // 自定义实现,只显示 `x` 和 `y`。 write!(f, "x: {}, y: {}", self.x, self.y) } } fn main() { let minmax = MinMax(0, 14); println!("比较结构体:"); println!("Display:{}", minmax); println!("Debug:{:?}", minmax); let big_range = MinMax(-300, 300); let small_range = MinMax(-3, 3); println!("大范围是 {big},小范围是 {small}", small = small_range, big = big_range); let point = Point2D { x: 3.3, y: 7.2 }; println!("比较点:"); println!("Display:{}", point); println!("Debug:{:?}", point); // 错误。虽然实现了 `Debug` 和 `Display`,但 `{:b}` 需要 // 实现 `fmt::Binary`。这行代码无法工作。 // println!("Point2D 的二进制表示是什么:{:b}?", point); }
因此,虽然实现了 fmt::Display
,但未实现 fmt::Binary
,所以无法使用。std::fmt
包含许多这样的traits
,每个都需要单独实现。更多详情请参阅 std::fmt
。
练习
查看上述示例的输出后,参考 Point2D
结构体,向示例中添加一个 Complex
结构体。以相同方式打印时,输出应为:
Display: 3.3 + 7.2i
Debug: Complex { real: 3.3, imag: 7.2 }