4.0 KiB
Debug and Display
All types which want to be printable must implement the std::fmt
formatting trait: std::fmt::Debug
or std::fmt::Display
.
Automatic implementations are only provided for types such as in the std
library. All others have to be manually implemented.
Debug
The implementation of Debug
is very straightfoward: All types can derive
the std::fmt::Debug
implementation. This is not true for std::fmt::Display
which must be manually implemented.
{:?}
must be used to print out the type which has implemented the Debug
trait.
// This structure cannot be printed either with `fmt::Display` or
// with `fmt::Debug`.
struct UnPrintable(i32);
// To make this struct printable with `fmt::Debug`, we can derive the automatic implementations provided by Rust
#[derive(Debug)]
struct DebugPrintable(i32);
- π
/* Fill in the blanks and Fix the errors */
struct Structure(i32);
fn main() {
// Types in std and Rust have implemented the fmt::Debug trait
println!("__ months in a year.", 12);
println!("Now __ will print!", Structure(3));
}
- ππ So
fmt::Debug
definitely makes one type printable, but sacrifices some elegance. Maybe we can get more elegant by replacing{:?}
with something else( but not{}
!)
#[derive(Debug)]
struct Person {
name: String,
age: u8
}
fn main() {
let person = Person { name: "Sunface".to_string(), age: 18 };
/* Make it output:
Person {
name: "Sunface",
age: 18,
}
*/
println!("{:?}", person);
}
- ππ We can also manually implement
Debug
trait for our types
#[derive(Debug)]
struct Structure(i32);
#[derive(Debug)]
struct Deep(Structure);
fn main() {
// The problem with `derive` is there is no control over how
// the results look. What if I want this to just show a `7`?
/* Make it print: Now 7 will print! */
println!("Now {:?} will print!", Deep(Structure(7)));
}
Display
Yeah, Debug
is simple and easy to use. But sometimes we want to customize the output appearance of our type. This is where Display
really shines.
Unlike Debug
, there is no way to derive the implementation of the Display
trait, we have to manually implement it.
Anotherthing to note: the placefolder for Display
is {}
not {:?}
.
- ππ
/* Make it work*/
use std::fmt;
struct Point2D {
x: f64,
y: f64,
}
impl fmt::Display for Point2D {
/* Implement.. */
}
impl fmt::Debug for Point2D {
/* Implement.. */
}
fn main() {
let point = Point2D { x: 3.3, y: 7.2 };
assert_eq!(format!("{}",point), "Display: 3.3 + 7.2i");
assert_eq!(format!("{:?}",point), "Debug: Complex { real: 3.3, imag: 7.2 }");
println!("Success!")
}
?
operator
Implementing fmt::Display
for a structure whose elements must be handled separately is triky. The problem is each write!
generates a fmt::Result
which must be handled in the same place.
Fortunately, Rust provides the ?
operator to help us eliminate some unnecessary codes for deaing with fmt::Result
.
- ππ
/* Make it work */
use std::fmt;
struct List(Vec<i32>);
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Extract the value using tuple indexing,
// and create a reference to `vec`.
let vec = &self.0;
write!(f, "[")?;
// Iterate over `v` in `vec` while enumerating the iteration
// count in `count`.
for (count, v) in vec.iter().enumerate() {
// For every element except the first, add a comma.
// Use the ? operator to return on errors.
if count != 0 { write!(f, ", ")?; }
write!(f, "{}", v)?;
}
// Close the opened bracket and return a fmt::Result value.
write!(f, "]")
}
}
fn main() {
let v = List(vec![1, 2, 3]);
assert_eq!(format!("{}",v), "[0: 1, 1: 2, 2: 3]");
println!("Success!")
}