1.3 Enseñar a hablar a las cosas
Esta traducción fue asistida por IA y revisada superficialmente. Si encuentras errores o algo no suena natural, escríbeme — lo agradezco.
Pedirle a una cosa que se describa es un deseo razonable, especialmente cuando algo va mal. Una tarea en el código no responderá a esa petición: la forma existe, los datos existen, pero no hay voz. El silencio no es una negativa. El silencio es cuando la pregunta nunca fue escuchada.
El intento
Los campos se imprimen actualmente uno por uno. A medida que crezcan el número de campos y
de tareas, eso se volverá engorroso rápidamente. Es más sensato pedirle a la tarea que se
describa como un todo. Rust tiene un modificador de formato especial para esto - {:?}:
println!("{:?}", task);
El compilador responde:
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`
Lo que sabe el compilador
{:?} es una petición: “descríbete en formato debug.” Para que un tipo pueda cumplirla,
debe saber cómo hacerlo. El compilador no puede inventar una descripción - necesita un
compromiso explícito.
En Rust, estos compromisos se llaman traits. Un trait es un conjunto de capacidades que un
tipo promete proporcionar. Debug es uno de ellos: un tipo que implementa Debug sabe cómo
describirse a sí mismo para depuración. Task aún no ha adquirido ese compromiso.
Los traits hacen mucho en Rust - el capítulo 3.1 los cubre en profundidad. Por ahora, una
cosa es suficiente: sin Debug, el compilador no sabe cómo manejar {:?}.
El conjuro
El compilador ya dio la respuesta en el mensaje de error: add #[derive(Debug)] to Task.
#[derive(Debug)]
struct Task {
id: u64,
title: String,
status: bool,
}
#[derive(Debug)] es un atributo que le pide al compilador que genere una implementación de
Debug automáticamente. Esto funciona porque todos los campos de Task - u64, String,
bool - ya saben describirse a sí mismos. El compilador ensambla sus descripciones juntas.
Ahora {:?} funciona:
println!("{:?}", task);
Task { id: 1, title: "Buy coffee", status: false }
También existe {:#?} - el mismo formato, pero con saltos de línea e indentación:
println!("{:#?}", task);
Task {
id: 1,
title: "Buy coffee",
status: false,
}
La tarea puede describirse a sí misma. Cuando algo vaya mal, habrá algo que imprimir.
El código completo de
tqpara este capítulo está en1-a-task/03-teaching-things-to-speak/.
Lore: Debug y Display
Debug no es el único trait para la salida. Rust tiene dos:
Debug- el formato del desarrollador. Se activa con{:?}o{:#?}. Muestra la estructura interna del tipo. Se genera automáticamente conderive.Display- el formato del usuario. Se activa con{}. Muestra lo que el lector del programa debe ver. No se genera automáticamente - hay que escribirlo a mano.
println!("{}", task) seguirá sin funcionar: Task no tiene Display. Aparecerá más
adelante - cuando la tarea aprenda a hablar en el idioma del usuario, no solo en el del
desarrollador.