En Rust no hay excepciones como en Java o C++; en su lugar se utilizan los tipos de envoltura Result y Option para devolver errores.
Result<T, E> — almacena ya sea un valor (Ok(T)), o un error (Err(E)). Se utiliza generalmente para operaciones que pueden no completarse correctamente (por ejemplo, entrada/salida de archivos).
Option<T> — para valores opcionales: ya sea Some(T), o None, sin información de error. Ejemplo:
fn divide(x: f64, y: f64) -> Option<f64> { if y == 0.0 { None } else { Some(x / y) } }
En Rust no hay excepciones al estilo try/catch para asegurar un flujo de errores transparente y controlado, y para no requerir un recolector de basura o un motor de unwind para mantener excepciones.
¿Por qué no debería usarse panic! para el manejo normal de errores?
Respuesta: panic! finaliza el flujo de ejecución, no permite recuperarse, y conduce a unwinding/abort. Si los errores se devuelven a través de Result, la parte que llama puede manejarlos. Ejemplo:
fn foo() -> Result<(), String> { Err("Algo salió mal".to_string()) } // en lugar de fn foo() { panic!("Algo salió mal"); }
Historia
En un microservicio para el procesamiento de imágenes, un desarrollador utilizó
panic!para manejar todas las situaciones inesperadas. Esto conducía a la finalización del servicio ante cualquier error en lugar de devolver una respuesta HTTP correcta al cliente con detalles del error.
Historia
En una herramienta para CLI se utilizó
unwrap()para toda la entrada/salida, sin manejar posibles errores. Como resultado, ante un error del sistema de archivos, el programa simplemente terminaba sin ningún mensaje o diagnóstico.
Historia
En un servicio de análisis intentaron usar Option para cada mínimo error, perdiendo información sobre los propios errores, dificultando la depuración. Después de cambiar a Result con errores en enumeraciones, fue más fácil encontrar y corregir errores.