1.3 Речь
Попросить вещь описать себя - разумное желание, особенно когда что-то идёт не так. Задача в коде на такую просьбу не ответит: форма есть, данные есть, но голоса нет. Молчание - не отказ. Молчание - это когда вопрос даже не был услышан.
Попытка
Поля сейчас печатаются по одному. Когда задач станет больше - и полей, и задач - это
быстро станет громоздким. Разумнее попросить задачу описать себя целиком. В Rust для этого
есть специальный форматный флаг - {:?}:
println!("{:?}", task);
Компилятор подсказывает:
error[E0277]: `Task` doesn't implement `Debug`
--> src/main.rs:XX:XX
|
XX | println!("{:?}", task);
| ^^^^ `Task` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Task`
= note: add `#[derive(Debug)]` to `Task` or manually `impl Debug for Task`
Что знает компилятор
{:?} - это запрос: “опиши себя в отладочном формате”. Чтобы выполнить его, тип должен
уметь это делать. Компилятор не может придумать описание за тип - он требует явного
обязательства.
В Rust такие обязательства называются трейтами. Трейт - это набор возможностей, которые тип
обязуется предоставить. Debug - один из них: тип, реализующий Debug, умеет описывать себя
для отладки. Task такого обязательства пока не давал.
Трейты в Rust делают многое - глава 3.1 разберёт их подробнее. Сейчас достаточно одного:
без Debug компилятор не знает, как обрабатывать {:?}.
Заклинание
Компилятор в сообщении об ошибке уже подсказал решение: add #[derive(Debug)] to Task.
#[derive(Debug)]
struct Task {
id: u64,
title: String,
status: bool,
}
#[derive(Debug)] - атрибут, который просит компилятор сгенерировать реализацию Debug
автоматически. Это возможно, потому что все поля Task - u64, String, bool - уже
умеют описывать себя. Компилятор собирает их описания вместе.
Теперь {:?} работает:
println!("{:?}", task);
Task { id: 1, title: "Buy coffee", status: false }
Есть ещё {:#?} - тот же формат, но с переносами строк и отступами:
println!("{:#?}", task);
Task {
id: 1,
title: "Buy coffee",
status: false,
}
Задача умеет описывать себя. Когда что-то пойдёт не так - будет что распечатать.
Полный код
tqдля этой главы -1-a-task/03-teaching-things-to-speak/.
Lore: Debug и Display
Debug - не единственный трейт для вывода. В Rust их два:
Debug- формат для разработчика. Активируется через{:?}или{:#?}. Показывает внутреннее устройство типа. Генерируется автоматически черезderive.Display- формат для пользователя. Активируется через{}. Показывает то, что читатель программы должен увидеть. Автоматически не генерируется - его нужно написать вручную.
println!("{}", task) сейчас всё ещё не сработает: Display у Task нет. Он появится
позже - когда задача научится говорить на языке пользователя, а не только разработчика.