Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Display

fmt::Debug навряд чи виглядає компактним і чистим, тому часто вигідно налаштувати вигляд виводу. Це робиться шляхом ручного виведення реалізації fmt::Display, який використовує позначку друку {}. Реалізація цього виглядає так:

#![allow(unused)]
fn main() {
// 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 може бути чистішим за fmt::Debug, але це створює проблему для бібліотеки std. Як слід відображати неоднозначні типи? Наприклад, якщо б бібліотека std реалізувала один стиль для всіх Vec<T>, яким мав би бути цей стиль? Чи був би він одним із цих двох?

  • Vec<path>: /:/etc:/home/username:/bin (розділено за :)
  • Vec<number>: 1,2,3 (розділено за ,)

Ні, тому що не існує ідеального стилю для всіх типів, і бібліотека std не бере на себе сміливість нав’язувати один. fmt::Display не реалізовано для Vec<T> або для будь-яких інших узагальнених контейнерів. Тоді для цих узагальнених випадків слід використовувати fmt::Debug.

Втім, це не проблема, тому що для будь-якого нового типу контейнера, який не є узагальненим, можна реалізувати fmt::Display.

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);

    // The following line would not compile: both `Debug` and `Display`
    // were implemented, but `{:b}` requires `fmt::Binary` to be
    // implemented, which it hasn't been for `Point2D`.
    // println!("What does Point2D look like in binary: {:b}?", point);
}

Отже, fmt::Display було реалізовано, але fmt::Binary — ні, і тому його не можна використовувати. std::fmt має багато таких traits, і кожен вимагає своєї реалізації. Це детальніше описано в std::fmt.

Activity

Після перевірки виводу наведеного вище прикладу, використайте структуру Point2D як зразок, щоб додати до прикладу структуру Complex. Коли її буде надруковано тим самим способом, вивід має бути таким:

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

Display: 4.7 -2.3i
Debug: Complex { real: 4.7, imag: -2.3 }

Бонус: Додайте пробіл після знаків +/-.

Підказки на випадок, якщо ви застрягнете:

  • Перевірте документацію для Sign/#/0 у std::fmt.
  • Бонус: Перевірте розгалуження if-else і функцію abs.

See also:

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