Introducción
En este laboratorio, se explica la funcionalidad de impresión formateada en Rust. El módulo std::fmt proporciona macros como format!, print!, println!, eprint! y eprintln! para manejar tareas de impresión. Estas macros permiten formatear texto con marcadores de posición que se reemplazan con los argumentos correspondientes. Se pueden utilizar argumentos posicionales y con nombre, y se pueden aplicar diferentes formatos utilizando caracteres de formato. Las macros también admiten la justificación del texto, el relleno de números y la fijación de la precisión para números decimales. El trato fmt::Display se utiliza para formatear texto de manera amigable para el usuario, mientras que el trato fmt::Debug se utiliza con fines de depuración. Rust también comprueba la corrección del formato en tiempo de compilación. Además, se menciona que implementar el trato fmt::Display implementa automáticamente el trato ToString, y los tipos personalizados deben implementar el trato fmt::Display para ser imprimibles. El laboratorio también incluye actividades para practicar el uso de las macros y los tratados de impresión formateada.
Nota: Si el laboratorio no especifica un nombre de archivo, puede utilizar cualquier nombre de archivo que desee. Por ejemplo, puede utilizar
main.rs, compilar y ejecutarlo conrustc main.rs &&./main.
Impresión formateada
La impresión se maneja mediante una serie de macros definidas en std::fmt, algunas de las cuales son las siguientes:
format!: escribe texto formateado enString.print!: es igual aformat!, pero el texto se imprime en la consola (io::stdout).println!: es igual aprint!, pero se agrega una nueva línea al final.eprint!: es igual aprint!, pero el texto se imprime en el error estándar (io::stderr).eprintln!: es igual aeprint!, pero se agrega una nueva línea al final.
Todas analizan el texto de la misma manera. Además, Rust comprueba la corrección del formato en tiempo de compilación.
fn main() {
// En general, `{}` se reemplazará automáticamente con cualquier
// argumento. Estos se convertirán en cadenas.
println!("{} días", 31);
// Se pueden utilizar argumentos posicionales. Especificar un entero dentro de `{}`
// determina qué argumento adicional se reemplazará. Los argumentos empiezan
// en 0 inmediatamente después de la cadena de formato.
println!("{0}, esto es {1}. {1}, esto es {0}", "Alice", "Bob");
// También se pueden utilizar argumentos con nombre.
println!("{subject} {verb} {object}",
object="el perro perezoso",
subject="el rápido zorro marrón",
verb="salta sobre");
// Se puede invocar un formato diferente especificando el carácter de formato
// después de un `:`.
println!("Base 10: {}", 69420); // 69420
println!("Base 2 (binaria): {:b}", 69420); // 10000111100101100
println!("Base 8 (octal): {:o}", 69420); // 207454
println!("Base 16 (hexadecimal): {:x}", 69420); // 10f2c
println!("Base 16 (hexadecimal): {:X}", 69420); // 10F2C
// Puedes justificar el texto a la derecha con un ancho especificado. Esto
// imprimirá " 1". (Cuatro espacios en blanco y un "1", para un ancho total de 5.)
println!("{number:>5}", number=1);
// Puedes rellenar los números con ceros adicionales,
println!("{number:0>5}", number=1); // 00001
// y ajustar a la izquierda invirtiendo el signo. Esto imprimirá "10000".
println!("{number:0<5}", number=1); // 10000
// Puedes utilizar argumentos con nombre en el especificador de formato agregando un `$`.
println!("{number:0>width$}", number=1, width=5);
// Rust incluso comprueba para asegurarse de que se utilicen el número correcto de argumentos.
println!("Mi nombre es {0}, {1} {0}", "Bond");
// FIXME ^ Agrega el argumento faltante: "James"
// Solo los tipos que implementan fmt::Display se pueden formatear con `{}`. Los tipos
// definidos por el usuario no implementan fmt::Display por defecto.
#[allow(dead_code)] // desactiva `dead_code` que advierte sobre el módulo no utilizado
struct Structure(i32);
// Esto no se compilará porque `Structure` no implementa
// fmt::Display.
// println!("Esta struct `{}` no se imprimirá...", Structure(3));
// TODO ^ Intenta descomentar esta línea
// Para Rust 1.58 y superior, puedes capturar directamente el argumento de una
// variable circundante. Al igual que lo anterior, esto imprimirá
// " 1", 4 espacios en blanco y un "1".
let number: f64 = 1.0;
let width: usize = 5;
println!("{number:>width$}");
}
std::fmt contiene muchos traits que gobiernan la visualización del texto. A continuación, se enumeran las formas básicas de dos de los más importantes:
fmt::Debug: utiliza el marcador{:?}. Formatea texto con fines de depuración.fmt::Display: utiliza el marcador{}. Formatea texto de manera más elegante y amigable para el usuario.
Aquí, usamos fmt::Display porque la biblioteca estándar de Rust proporciona implementaciones para estos tipos. Para imprimir texto de tipos personalizados, se requieren más pasos.
Implementar el trato fmt::Display implementa automáticamente el trato ToString que nos permite convertir el tipo a String.
En la línea 43, #[allow(dead_code)] es un [atributo] que solo se aplica al módulo posterior a él.
Actividades
- Corrige el problema en el código anterior (ver FIXME) para que se ejecute sin errores.
- Intenta descomentar la línea que intenta formatear la struct
Structure(ver TODO) - Agrega una llamada a la macro
println!que imprima:Pi es aproximadamente 3.142controlando el número de decimales mostrados. Con fines de este ejercicio, utilizalet pi = 3.141592como una estimación de pi. (Pista: es posible que necesites revisar la documentación destd::fmtpara establecer el número de decimales a mostrar)
Resumen
¡Felicidades! Has completado el laboratorio de Impresión Formateada. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.