Escribiendo mensajes de error estándar en lugar del output estándar
En este momento, estamos escribiendo toda nuestro output en la terminal usando
la macro println!
. En la mayoría de las terminales, hay dos tipos de output:
output estándar (stdout
) para información general y error estándar
(stderr
) para mensajes de error. Esta distinción permite a los usuarios
elegir dirigir el output exitoso de un programa a un archivo pero aun así
imprimir mensajes de error en la pantalla.
La macro println!
solo es capaz de imprimir en el output estándar, así que
tenemos que usar algo más para imprimir en el error estándar.
Revisando donde se escriben los errores
Primero, observemos como el contenido impreso por minigrep
está siendo
escrito en el output estándar, incluyendo cualquier mensaje de error que
queramos escribir en el error estándar. Haremos eso redirigiendo el output
estándar a un archivo mientras causamos un error intencionalmente. No
redirigiremos el error estándar, así que cualquier contenido enviado al error
estándar continuará mostrándose en la pantalla.
Los programas de línea de comandos se espera que envíen mensajes de error al error estándar así que podemos ver los mensajes de error en la pantalla incluso si redirigimos el output estándar a un archivo. Nuestro programa no se está comportando bien: estamos a punto de ver que guarda los mensajes de error en un archivo en su lugar!
Para demostrar este comportamiento, ejecutaremos el programa con >
y la ruta
del archivo, output.txt, al que queremos redirigir el output estándar. No
pasaremos ningún argumento, lo que debería causar un error:
$ cargo run > output.txt
La sintaxis >
le dice a la shell que escriba el contenido del output estándar
en output.txt en lugar de la pantalla. No vimos el mensaje de error que
esperábamos impreso en la pantalla, así que eso significa que debe haber
terminado en el archivo. Esto es lo que contiene output.txt:
Problem parsing arguments: not enough arguments
Sí, nuestro mensaje de error está siendo impreso en el output estándar. Es mucho más útil para mensajes de error como este ser impresos en el error estándar así que solo los datos de una ejecución exitosa terminen en el archivo. Cambiaremos eso.
Imprimiendo errores en el error estándar
Usaremos el código en el Listado 12-24 para cambiar como los mensajes de error
son impresos. Debido al refactor que hicimos anteriormente en este capítulo,
todo el código que imprime mensajes de error está en una función, main
. La
librería estándar provee la macro eprintln!
que imprime en el flujo de error
estándar, así que cambiaremos los dos lugares donde estábamos llamando
println!
para imprimir errores usando eprintln!
en su lugar.
Filename: src/main.rs
use std::env;
use std::process;
use minigrep::Config;
fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::build(&args).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
process::exit(1);
});
if let Err(e) = minigrep::run(config) {
eprintln!("Application error: {e}");
process::exit(1);
}
}
Listing 12-24: Escribiendo mensajes de error en el
error estándar en lugar del output estándar utilizando eprintln!
Ahora, ejecutaremos el programa de la misma manera que antes, sin pasar ningún
argumento y redirigiendo el output estándar con >
:
$ cargo run > output.txt
Problem parsing arguments: not enough arguments
Ahora podemos ver el mensaje de error en la pantalla y output.txt no contiene nada, que es el comportamiento que esperamos de los programas de línea de comandos.
Ejecutemos el programa otra vez con argumentos que no causen un error pero aun así redirigiendo el output estándar a un archivo, como así:
$ cargo run -- to poem.txt > output.txt
No veremos ningún output en la terminal, y output.txt contendrá nuestros resultados:
Filename: output.txt
Are you nobody, too?
How dreary to be somebody!
Esto demuestra que ahora estamos usando el output estándar para output exitoso y el error estándar para output de error como es apropiado.
Resumen
En este capítulo repasó algunos de los conceptos principales que has aprendido
hasta ahora y cubrió como realizar operaciones de I/O comunes en Rust. Al usar
argumentos de línea de comandos, archivos, variables de ambiente, y la macro
eprintln!
para imprimir errores, ahora estás preparado para escribir
aplicaciones de línea de comandos. Combinado con los conceptos de capítulos
anteriores, tu código estará bien organizado, almacenará datos efectivamente en
las estructuras de datos apropiadas, manejará errores de manera agradable, y
estará bien testeado.
A continuación, exploraremos algunas características de Rust que fueron influenciadas por lenguajes funcionales: closures e iterators.