summaryrefslogtreecommitdiffstats
path: root/src/doc/rust-by-example/src/hello/print/print_display.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc/rust-by-example/src/hello/print/print_display.md')
-rw-r--r--src/doc/rust-by-example/src/hello/print/print_display.md129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/doc/rust-by-example/src/hello/print/print_display.md b/src/doc/rust-by-example/src/hello/print/print_display.md
new file mode 100644
index 000000000..fdae9648a
--- /dev/null
+++ b/src/doc/rust-by-example/src/hello/print/print_display.md
@@ -0,0 +1,129 @@
+# 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`][fmt], which uses the `{}` print marker. Implementing it
+looks like this:
+
+```rust
+// Import (via `use`) the `fmt` module to make it available.
+use std::fmt;
+
+// Define a structure for which `fmt::Display` will be implemented. This is
+// a tuple struct named `Structure` that contains an `i32`.
+struct Structure(i32);
+
+// To use the `{}` marker, the trait `fmt::Display` must be implemented
+// manually for the type.
+impl fmt::Display for Structure {
+ // This trait requires `fmt` with this exact signature.
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // 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.0)
+ }
+}
+```
+
+`fmt::Display` may be cleaner than `fmt::Debug` but this presents
+a problem for the `std` library. How should ambiguous types be displayed?
+For example, if the `std` library implemented a single style for all
+`Vec<T>`, what style should it be? Would it be either of these two?
+
+* `Vec<path>`: `/:/etc:/home/username:/bin` (split on `:`)
+* `Vec<number>`: `1,2,3` (split on `,`)
+
+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.
+
+```rust,editable
+use std::fmt; // Import `fmt`
+
+// A structure holding two numbers. `Debug` will be derived so the results can
+// be contrasted with `Display`.
+#[derive(Debug)]
+struct MinMax(i64, i64);
+
+// Implement `Display` for `MinMax`.
+impl fmt::Display for MinMax {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // Use `self.number` to refer to each positional data point.
+ write!(f, "({}, {})", self.0, self.1)
+ }
+}
+
+// Define a structure where the fields are nameable for comparison.
+#[derive(Debug)]
+struct Point2D {
+ x: f64,
+ y: f64,
+}
+
+// Similarly, implement `Display` for `Point2D`
+impl fmt::Display for Point2D {
+ 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 = Point2D { x: 3.3, y: 7.2 };
+
+ println!("Compare points:");
+ println!("Display: {}", point);
+ println!("Debug: {:?}", point);
+
+ // Error. Both `Debug` and `Display` were implemented, but `{:b}`
+ // requires `fmt::Binary` to be implemented. This will not work.
+ // 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`][traits] and
+each requires its own implementation. This is detailed further in
+[`std::fmt`][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:
+
+```txt
+Display: 3.3 + 7.2i
+Debug: Complex { real: 3.3, imag: 7.2 }
+```
+
+### See also:
+
+[`derive`][derive], [`std::fmt`][fmt], [`macros`][macros], [`struct`][structs],
+[`trait`][traits], and [`use`][use]
+
+[derive]: ../../trait/derive.md
+[fmt]: https://doc.rust-lang.org/std/fmt/
+[macros]: ../../macros.md
+[structs]: ../../custom_types/structs.md
+[traits]: https://doc.rust-lang.org/std/fmt/#formatting-traits
+[use]: ../../mod/use.md