Display
fmt::Debug hardly looks compact and clean, so it is often advantageous to
customize the output appearance. This is done by manually implementing
fmt::Display, which uses the {} print marker. Implementing it
looks like this:
// Import (via `use`) the `fmt` module to make it available.
use core::fmt;
// Define a structure for which `fmt::Display` will be implemented. This is
// a tuple struct named `Structure` that contains an integer.
#[derive(Drop)]
struct Structure {
value: u32,
}
// To use the `{}` marker, the trait `fmt::Display` must be implemented
// manually for the type.
impl StructureDisplay of fmt::Display<Structure> {
// This trait requires `fmt` with this exact signature.
fn fmt(self: @Structure, ref f: fmt::Formatter) -> Result<(), fmt::Error> {
// 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.value)
}
}
fmt::Display may be cleaner than fmt::Debug but this presents
a problem for the core library. How should ambiguous types be displayed?
For example, if the core library implemented a single style for all
Array<T>, what style should it be? Would it be either of these two?
Array<ContractAddress>:0x123, 0x456, 0x789(using hex representation)Array<number>:1,2,3(using decimal representation)
No, because there is no ideal style for all types and the core library
doesn't presume to dictate one. fmt::Display is not implemented for Array<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 core::fmt; // Import `fmt`
// A structure holding two numbers. `Debug` will be derived so the results can
// be contrasted with `Display`.
#[derive(Debug, Drop)]
struct MinMax {
min: i64,
max: i64,
}
// Implement `Display` for `MinMax`.
impl MinMaxDisplay of fmt::Display<MinMax> {
fn fmt(self: @MinMax, ref f: fmt::Formatter) -> Result<(), fmt::Error> {
// Use `self.number` to refer to each positional data point.
write!(f, "({}, {})", *self.min, *self.max)
}
}
// Define a structure where the fields are nameable for comparison.
#[derive(Debug, Drop)]
struct Point2D {
x: i64,
y: i64,
}
// Similarly, implement `Display` for `Point2D`.
impl Point2DDisplay of fmt::Display<Point2D> {
fn fmt(self: @Point2D, ref f: fmt::Formatter) -> Result<(), fmt::Error> {
// Customize so only `x` and `y` are denoted.
write!(f, "x: {}, y: {}", *self.x, *self.y)
}
}
fn main() {
let minmax = MinMax { min: 0, max: 14 };
println!("Compare structures:");
println!("Display: {}", minmax);
println!("Debug: {:?}", minmax);
let big_range = MinMax { min: -300, max: 300 };
let small_range = MinMax { min: -3, max: 3 };
println!("The big range is {} and the small is {}", big_range, small_range);
let point = Point2D { x: 3, y: 7 };
println!("Compare points:");
println!("Display: {}", point);
// Error. Both `Debug` and `Display` were implemented, but `{:x}`
// requires `fmt::LowerHex` to be implemented. This will not work.
// println!("What does Point2D look like in binary: {:x}?", point);
}
So, fmt::Display has been implemented but fmt::LowerHex has not, and therefore
cannot be used. core::fmt has many such traits and each requires
its own implementation. This is detailed further in core::fmt.
Activity
After checking the output of the above example, use the Point2D struct as a
guide to add a Complex struct to the example. When printed in the same
way, the output should be:
Display: 3 + 7i
Debug: Complex { real: 3, imag: 7 }