Lecciones del módulo (2/2)
Gestión de errores y el operador ?
La filosofía de Rust fomenta reconocer explícitamente la posibilidad de errores y estructurar el código para manejarlos antes de compilar el programa.
Los errores en Rust se dividen en dos categorías principales: errores irrecuperables (que provocan un bloqueo inmediato mediante el pánico panic!) y errores recuperables (manejados mediante el tipo Result<T, E>).
El tipo Resultado<T, E> y la coincidencia de patrones
La mayoría de los errores recuperables devuelven un tipo Result<T, E> que es una enumeración definida como:
enum Result<T, E> {
Ok(T),
Err(E),
}
Podemos usar la coincidencia de patrones para inspeccionar el resultado:
use std::fs::File;
fn main() {
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => panic!("Problema nell'aprire il file: {:?}", error),
};
}
Propagación de errores con el operador ?
Cuando implementamos una función, en lugar de manejar el error directamente dentro de ella, a menudo queremos devolver el error a la persona que llama para que pueda decidir qué hacer. Este proceso se llama propagación de errores.
Rust proporciona el operador ? como atajo sintáctico para la propagación de errores. Si el valor de Result es Ok, la expresión devuelve el valor dentro de Ok; si es Err, toda la función actual devuelve el error Err como si hubiéramos usado un return Err(...).
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = File::open("username.txt")?;
let mut username = String::new();
username_file.read_to_string(&mut username)?;
Ok(username)
}
[!IMPORTANTE] El operador
?solo se puede utilizar en funciones que devuelven un tipo compatible con el valor al que se aplica (normalmenteResult,Optiono tipos que implementanFromResidual).
Errores personalizados
Podemos definir nuestros propios tipos de error implementando el rasgo std::fmt::Display (y opcionalmente std::error::Error) para proporcionar una representación del error legible por humanos:
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Errore: {}", self.details)
}
}
impl std::error::Error for MyError {}
Pruébalo tú mismo
Ejercicio 1: Leer un archivo con ? operador
Complete la función read_username_from_file para usar ? operador. para propagar los errores generados al abrir el archivo y leer su contenido en la cadena del nombre de usuario.
Mostrar pista
Agregue el carácter `?` después de `File::open(...)` y después de `username_file.read_to_string(...)` para propagar errores.
Solución disponible después de 3 intentos
Ejercicio 2: Analizar y procesar un número
Escriba una función llamada parse_and_double que tome como entrada una referencia de cadena &str y devuelva un Resultado<i32, std::num::ParseIntError>. La función debe analizar la cadena con val.parse::<i32>() usando ? para propagar el error de análisis y, si tiene éxito, devolver el valor duplicado incluido en Ok.
Mostrar pista
Utilice `val.parse::<i32>()?` para convertir la cadena propagando el error, luego devuelva `Ok(num * 2)`.
Solución disponible después de 3 intentos
Ejercicio 3: Definir un error personalizado
Defina una estructura vacía llamada CustomError. Implemente el rasgo std::fmt::Display escribiendo el mensaje 'Se produjo un error personalizado' dentro del método fmt.
Mostrar pista
Declare `struct CustomError;`e implemente Display escribiendo`write!(f, "Si e verificato un errore personalizzato")`en el método `fmt`.
Solución disponible después de 3 intentos