← Índice

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 tq para este capítulo está en 1-a-task/03-teaching-things-to-speak/.


Lore: Debug y Display

Debug no es el único trait para la salida. Rust tiene dos:

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.