El trait Debug
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 35 de 61.
La biblioteca estándar de Rust viene con muchos traits predefinidos que proporcionan funcionalidad común. Uno de los más útiles para el desarrollo es el trait Debug, que permite imprimir el contenido de una struct para su inspección.
Si intentas imprimir una estructura personalizada directamente, Rust no sabrá cómo mostrarla:
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // ¡Error! Debug no implementado
El formateador {:?} requiere el trait Debug. En lugar de implementarlo manualmente, Rust proporciona un atajo: el atributo #[derive]. Colócalo directamente encima de la definición de tu struct:
#[derive(Debug)]
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // Player { name: "Alice", score: 100 }
El atributo #[derive(Debug)] le indica al compilador que genere automáticamente la implementación de Debug. Esto funciona siempre que todos los campos de tu struct también implementen Debug (lo cual hacen la mayoría de los tipos estándar).
Para obtener una salida más legible con estructuras anidadas, utiliza {:#?} para una impresión formateada (pretty-printing):
println!("{:#?}", p);
// Player {
// name: "Alice",
// score: 100,
// }
Derivar Debug es esencial durante el desarrollo: te permite inspeccionar rápidamente tus datos sin escribir código de formato personalizado.
Desafío
Fácil¡Hagamos que tus structs sean inspeccionables derivando el trait Debug! Crearás un sistema de inventario simple donde los elementos se pueden imprimir para fines de depuración.
Organizarás tu código en dos archivos:
inventory.rs: Define una estructuraItempública con dos campos públicos:name(String) yquantity(u32). Usa el atributo#[derive(Debug)]para implementar automáticamente el trait Debug para tu estructura.main.rs: Incorpora tu módulo de inventario y crea una instancia deItemutilizando las entradas proporcionadas. Imprime el elemento usando el formateador de depuración{:?}para mostrar su estructura interna.
¡Lo bueno de derivar Debug es que Rust genera automáticamente el código de formateo por ti, sin necesidad de implementación manual! Tu estructura solo necesita el atributo y se vuelve imprimible con {:?}.
Tu salida debería mostrar el elemento en el formato de depuración de Rust:
Item { name: "{name}", quantity: {quantity} }Por ejemplo, con las entradas Keyboard y 15:
Item { name: "Keyboard", quantity: 15 }Recibirás dos entradas: el nombre del elemento y la cantidad (analízala como u32).
Hoja de referencia
El trait Debug permite imprimir el contenido de una estructura para su inspección utilizando el formateador {:?}.
Usa el atributo #[derive(Debug)] para implementar automáticamente Debug para tu estructura:
#[derive(Debug)]
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // Player { name: "Alice", score: 100 }
Para una salida con un formato más legible (pretty-print), usa {:#?}:
println!("{:#?}", p);
// Player {
// name: "Alice",
// score: 100,
// }
El atributo #[derive(Debug)] funciona siempre que todos los campos de tu estructura también implementen Debug, lo cual hacen la mayoría de los tipos estándar.
Pruébalo tú mismo
mod inventory;
use inventory::Item;
fn main() {
// Leer entrada
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: Crear una instancia de Item con el nombre y la cantidad dados
// TODO: Imprimir el artículo usando el formateador de depuración {:?}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Métodos y Comportamiento
Intro a Bloques de ImplementaciónEl Parámetro SelfMétodos MutablesFunciones AsociadasMúltiples Bloques de ImplementaciónEncadenamiento de MétodosResumen - Acciones de Rectángulo4Proyecto: Mascota virtual
Definir la mascotaAlimentar a la mascota7Traits estándar
El trait DebugEl trait DisplayClone y CopyTraits de igualdadResumen - Punto imprimible10Proyecto: Sistema de documentos
El Trait DrawComponente de texto2Encapsulamiento y módulos
Conceptos básicos de módulosLa palabra clave PublicCampos privadosGettersSettersRepaso - Casillero seguro5Genéricos
Estructuras genéricasMétodos genéricosMúltiples tipos genéricosFunciones genéricasResumen - Punto de coordenadas8Traits como límites
Sintaxis de límites de traitsLímites múltiplesLa cláusula whereRetornar tipos con traitsResumen: Impresora genérica11Patrones de diseño en Rust
Patrón NewtypeComposiciónEl Trait DropFrom e IntoResumen - Mock de Smart Pointer3Enums avanzados
Enums con datosMétodos en EnumsCoincidencia de variantes de datosEl Enum Option revisitadoResumen - Enum Shape6Definición de Traits
¿Qué es un Trait?Implementación de TraitsImplementaciones por defectoSobrescribir valores por defectoTraits con parámetrosResumen - Reproductor multimedia