调试(Debug)

所有的类型,若想用 std::fmt 的格式化打印,都要求实现至少一个可打印的 traits。仅有一些类型提供了自动实现,比如 std 库中的类型。所有其他类型都必须手动实现。

fmt::Debug 这个 trait 使这项工作变得相当简单。所有类型都能推导(derive,即自动创建)fmt::Debug 的实现。但是 fmt::Display 需要手动实现。

  1. // 这个结构体不能使用 `fmt::Display` 或 `fmt::Debug` 来进行打印。
  2. struct UnPrintable(i32);
  3. // `derive` 属性会自动创建所需的实现,使这个 `struct` 能使用 `fmt::Debug` 打印。
  4. #[derive(Debug)]
  5. struct DebugPrintable(i32);

所有 std 库类型都天生可以使用 {:?} 来打印:

  1. // 推导 `Structure` 的 `fmt::Debug` 实现。
  2. // `Structure` 是一个包含单个 `i32` 的结构体。
  3. #[derive(Debug)]
  4. struct Structure(i32);
  5. // 将 `Structure` 放到结构体 `Deep` 中。然后使 `Deep` 也能够打印。
  6. #[derive(Debug)]
  7. struct Deep(Structure);
  8. fn main() {
  9. // 使用 `{:?}` 打印和使用 `{}` 类似。
  10. println!("{:?} months in a year.", 12);
  11. println!("{1:?} {0:?} is the {actor:?} name.",
  12. "Slater",
  13. "Christian",
  14. actor="actor's");
  15. // `Structure` 也可以打印!
  16. println!("Now {:?} will print!", Structure(3));
  17. // 使用 `derive` 的一个问题是不能控制输出的形式。
  18. // 假如我只想展示一个 `7` 怎么办?
  19. println!("Now {:?} will print!", Deep(Structure(7)));
  20. }

所以 fmt::Debug 确实使这些内容可以打印,但是牺牲了一些美感。Rust 也通过 {:#?} 提供了 “美化打印” 的功能:

  1. #[derive(Debug)]
  2. struct Person<'a> {
  3. name: &'a str,
  4. age: u8
  5. }
  6. fn main() {
  7. let name = "Peter";
  8. let age = 27;
  9. let peter = Person { name, age };
  10. // 美化打印
  11. println!("{:#?}", peter);
  12. }

你可以通过手动实现 fmt::Display 来控制显示效果。

参见:

attributes, derive, std::fmtstruct