Rust by Example中文

1.2.2 Display

fmt::Debug 看上去相当紧凑干净,它们实现定义输出很方便。它实际是通过{}打印标识实现的fmt::Display. 实现过程类似于下列代码:

// 通过`use`导入`fmt`模块
use std::fmt;

//  定义将实现`fmt::Display`的结构体.
// 这是一个简单包含`i32`类型参数的元组(tuple)结构体 `Structure`.
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 (,分隔)

No, because there is no ideal style for all types and the std library doesn't presume to dictate one. fmt::Display is not implemented for Vec<T> or for any other generic containers. fmt::Debug must then be used for these generic cases.

This is not a problem though because for any new container type which is not generic,fmt::Display can be implemented.

use std::fmt; // 导入 `fmt` // derive `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 Point2 { x: f64, y: f64, } // 同样,为Point2实现Display impl fmt::Display for Point2 { 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 = Point2 { x: 3.3, y: 7.2 }; println!("Compare points:"); println!("Display: {}", point); println!("Debug: {:?}", point); // Error. // `Debug` 和 `Display`都能被实现,但是`{:b}`需要实现`fmt::Binary` //下面这行将不会被执行 // println!("What does Point2D look like in binary: {:b}?", point); }

So, fmt::Display has been implemented but fmt::Binary has not, and therefore cannot be used. std::fmt has many such traits and each requires its own implementation. This is detailed further in std::fmt.

Activity

After checking the output of the above example, use the Point2 struct as guide to add a Complex struct to the example. When printed in the same way, the output should be:

Display: 3.3 + 7.2i
Debug: Complex { real: 3.3, imag: 7.2 }

See also

derive, std::fmt, macros, struct, trait, and use