Трейты Debug и fmt::Display

Последнее обновление: 06.06.2024

Трейт Debug

Трейт Debug позволяет вывести данные на консоль в удобном для разработчиков виде. Что довольно удобно для отладки. Для применения трейта Debug при выводе на консоль, например, с помощью макроса println! внутри фигурных указывается спецификатор :?. Например:

fn main() {
    let tom = ("Tom", 40);
    println!("{:?}", tom);  // ("Tom", 40)
}

В данном случае спецификатор :? применяется для вывода на консоль кортежа с двумя элементами. И, таким образом, мы сможем увидеть весь кортеж.

Однако не все типы мы можем так вывести на консоль. Например, что, если у нас есть структура со множеством полей, и мы хотим вывести структуру в удобочитаемом виде без необходимости выводить каждое поле по отдельности:

struct Person
{
    name: String,
	age: u8
}

fn main() {
    let tom = Person{name:"Tom".to_string(), age: 40};
    println!("{:?}", tom);  // ! Ошибка - Person cannot be formatted using `{:?}`
}

Здесь при попытке вывести значение структуры Person мы столкнемся с ошибкой, поскольку эта структура не реализует трейт Debug.

К счастью, реализовать этот трейт не так сложно. Для этого Rust предоставляет атрибут #[derive(Debug)], который надо применить к структуре:

#[derive(Debug)]
struct Person
{
    name: String,
	age: u8
}

fn main() {
    let tom = Person{name:"Tom".to_string(), age: 40};
    println!("{:?}", tom);  // Person { name: "Tom", age: 40 }
}

И консоль нам выведет

Person { name: "Tom", age: 40 }

И мы можем пойти дальше и вывести данные в более удобочитаемом виде, применив спецификатор :#?

println!("{:#?}", tom);

Консольный вывод:

Person {
    name: "Tom",
    age: 40,
}

Стоит отметить, что есть еще один способ вывести значение в формате отладки — использовать макрос dbg!. При этом данный макрос также выводит файл и номер строки, где находится текущий вызов макроса dbg!. Однако стоит учитывать, что этот макрос получает владение над передаваемым значением, поэтому лучше в этот макрос передать ссылку на значение:

#[derive(Debug)]
struct Person
{
    name: String,
	age: u8
}

fn main() {
    let tom = Person{name:"Tom".to_string(), age: 40};
    dbg!(&tom);
}

Консольный вывод:

[main.rs:10:5] &tom = Person {
    name: "Tom",
    age: 40,
}

fmt::Display

Реализация трейта fmt::Display также позволяет выводить нам на консоль некоторое значение, только с помощью плейсхолдера "{}". Многие встроенные типы реализуют этот трейт. Посмотрим, как его реализовать для кастомных типов:

use std::fmt;

struct Person
{
    name: String,
	age: u8
}
impl fmt::Display for Person {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Person {} (age: {})", self.name, self.age)
    }
}
fn main() {
    let tom = Person{name:"Tom".to_string(), age: 40};
    println!("{}", tom);  // Person Tom (age: 40)
}

Здесь трейт fmt::Display также реализуется для структуры Person. Реализация трейта представляет реализацию функции fmt(), которая принимает два параметра - ссылку на текущий объект структуры - &self и форматировщик fmt::Formatter. Функция возвращает значение типа fmt::Result. И наша реализация довольно проста - с помощью макроса write! определяем, как данные структуры Person будут выводиться на консоль.

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850