Трейт Debug
Часть раздела Object Oriented Programming путешествия по Rust на Coddy — урок 35 из 61.
Стандартная библиотека Rust поставляется со множеством предопределённых типажей, которые обеспечивают общую функциональность. Одним из наиболее полезных для разработки является типаж Debug, который позволяет выводить содержимое структуры для проверки.
Если вы попытаетесь вывести пользовательскую структуру напрямую, Rust не будет знать, как её отобразить:
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // Ошибка! Debug не реализован
Форматировщик {:?} требует наличия трейта Debug. Вместо того чтобы реализовывать его вручную, Rust предоставляет сокращение — атрибут #[derive]. Разместите его непосредственно над определением вашей структуры:
#[derive(Debug)]
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // Player { name: "Alice", score: 100 }
Атрибут #[derive(Debug)] сообщает компилятору автоматически сгенерировать реализацию Debug. Это работает до тех пор, пока все поля в вашей структуре также реализуют Debug (что делает большинство стандартных типов).
Для более читаемого вывода вложенных структур используйте {:#?} для «красивой» печати (pretty-printing):
println!("{:#?}", p);
// Player {
// name: "Alice",
// score: 100,
// }
Автоматический вывод Debug необходим во время разработки — он позволяет быстро проверять ваши данные без написания собственного кода форматирования.
Задание
ЛегкоДавайте сделаем ваши структуры доступными для инспекции, реализовав трейт Debug с помощью макроса derive! Вы создадите простую систему инвентаризации, где элементы можно выводить на печать для целей отладки.
Вы организуете свой код в двух файлах:
inventory.rs: Определите публичную структуруItemс двумя публичными полями:name(String) иquantity(u32). Используйте атрибут#[derive(Debug)], чтобы автоматически реализовать трейт Debug для вашей структуры.main.rs: Подключите модуль inventory и создайте экземплярItem, используя предоставленные входные данные. Выведите элемент, используя отладочный форматер{:?}, чтобы отобразить его внутреннюю структуру.
Прелесть использования derive(Debug) заключается в том, что Rust автоматически генерирует код форматирования за вас — ручная реализация не требуется! Вашей структуре просто нужен этот атрибут, и она становится доступной для вывода с помощью {:?}.
Ваш вывод должен отображать элемент в отладочном формате Rust:
Item { name: "{name}", quantity: {quantity} }Например, при входных данных Keyboard и 15:
Item { name: "Keyboard", quantity: 15 }Вы получите два входных значения: название товара и количество (преобразуйте в u32).
Шпаргалка
Трейт Debug позволяет выводить содержимое структуры для проверки с использованием форматировщика {:?}.
Используйте атрибут #[derive(Debug)] для автоматической реализации Debug для вашей структуры:
#[derive(Debug)]
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // Player { name: "Alice", score: 100 }
Для вывода с улучшенным форматированием (pretty-print) используйте {:#?}:
println!("{:#?}", p);
// Player {
// name: "Alice",
// score: 100,
// }
Атрибут #[derive(Debug)] работает до тех пор, пока все поля в вашей структуре также реализуют Debug, что характерно для большинства стандартных типов.
Попробуйте сами
mod inventory;
use inventory::Item;
fn main() {
// Чтение входных данных
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
let mut quantity_str = String::new();
std::io::stdin().read_line(&mut quantity_str).expect("Failed to read line");
let quantity: u32 = quantity_str.trim().parse().expect("Failed to parse quantity");
// TODO: Создать экземпляр Item с заданным именем и количеством
// TODO: Вывести элемент, используя отладочный форматтер {:?}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media Player