Rust se basa en la gestión explícita de errores: las excepciones están ausentes, en su lugar se utiliza el valor de retorno Result<T, E>. Esto garantiza la seguridad y la previsibilidad del código.
Historia del tema:
Muchos lenguajes han seguido el camino de las excepciones, lo que ha llevado a situaciones inesperadas y a la necesidad de manejar las excepciones de forma explícita en tiempo de ejecución. Desde el principio, Rust apostó por el control a través de tipos, todos los errores deben ser parte de la firma de la función.
Problema:
El objetivo principal es escribir código en el que los errores no sean ignorados ni enmascarados, no existen funciones "que fallen", pero al mismo tiempo el código sigue siendo compacto y legible. Es necesario propagar correctamente los errores hacia arriba, sin perder información sobre su tipo, y sin confundir la lógica.
Solución:
La herramienta clave es el tipo Result<T, E> y el operador ?, que "desenvuelve" automáticamente el resultado: en caso de error, se produce una salida inmediata de la función con la devolución del error, y en caso de éxito se devuelve el valor.
Ejemplo de código:
fn read_number(file: &str) -> Result<i32, std::io::Error> { let content = std::fs::read_to_string(file)?; let num: i32 = content.trim().parse()?; Ok(num) }
Características clave:
.map_err() y otros métodos)¿Se puede usar ? en funciones que devuelven Unit (void)?
No, el operador ? solo es válido dentro de funciones que retornan Result o Option. Si la función devuelve (), no se puede usar ?.
¿Qué sucederá si los tipos de error en varias llamadas con ? son diferentes?
Se producirá un error de compilación: el tipo de error debe estar claramente definido. Se debe o bien convertir todos los errores a un único tipo a través de .map_err() o usar thiserror, o describir un envoltorio enum a nivel de API. Ejemplo:
fn foo() -> Result<_, MyError> { let a = bar()?; let b = baz().map_err(MyError::Baz)?; Ok(…) }
¿Qué hay de peligroso en .unwrap() en la lógica interna?
Existe una creencia errónea de que en el código "principal" se puede usar unwrap() sin cuidado, "definitivamente no fallará". En realidad, incluso un pequeño error invisible puede causar pánico en tiempo de ejecución, afectando la seguridad del programa.
unwrap/expect, especialmente en la lógica interna?En el código de producción se dejaron muchos unwrap() después de una depuración rápida. Como resultado, la aplicación fallaba en cualquier error de análisis debido a una entrada incorrecta del usuario.
Pros:
Contras:
Se utilizó toda la pilas Result<T, E> con una descripción explícita de errores y se aplicaron solo ? y .map_err(), manteniendo toda la información sobre fallos.
Pros:
Contras: