Saltar al contenido principal

Error Handling

Option<T>

  • Option<T> es una enumeración que representa la posibilidad de que un valor sea algo o nada
  • Option<T> es un tipo genérico, lo que significa que puede contener cualquier tipo de valor
  • No se crea el enum Option<T> en el código, ya que es parte de la librería estándar de Rust
enum Option<T> {
Some(T), // Devuelve un valor
  None,    // No devuelve nada
}
fn main() {  

    fn divide(numerador: f64, denominador: f64) -> Option<f64> {
        if denominador == 0.0 {
            None
        } else {
            Some(numerador / denominador)
        }
    }

    let resultado = divide(10.0, 2.0);

    match resultado {
        Some(x) => println!("El resultado es: {}", x),
        None => println!("No se puede dividir por cero"),
    }
}
  • match: Usado para manejar tanto el caso de éxito (Some) como el de error (None).
  • if let: Útil cuando solo te interesa el caso de éxito (Some).
  • .unwrap(): Extrae el valor de Some, pero causará un panic si es None.
  • .unwrap_or(): Devuelve el valor de Some, o un valor por defecto si es None.
  • .map(): Aplica una transformación al valor dentro de Some, y deja None intacto.
fn divide(a: f64, b: f64) -> Option<f64> {
if b == 0.0 {
None // Caso de error, no se puede dividir por cero
} else {
Some(a / b) // Resultado exitoso
}
}

match

match para manejar tanto el caso Some(T) como el caso None, y luego guardamos los resultados en variables.

fn main() {
let result = divide(10.0, 2.0);

// `match` para manejar tanto el caso de Some como None
// Si es Some, guardamos el valor en `value`
// Si es None, asignamos un valor por defecto o manejamos el error
let value = match result {
Some(v) => v,
None => {
let error_message = "No se pudo realizar la división".to_string();
eprintln!("{}", error_message);
0.0 // Retornamos un valor por defecto para continuar
}
};

// Ahora `value` contiene el resultado de la operación o un valor por defecto
let final_result = value;
// Puedes usar `final_result` para continuar el flujo de tu aplicación
}

if let

Si solo te interesa manejar el caso de éxito (Some(T)), puedes usar if let y almacenar el resultado en una variable.

fn main() {
let result = divide(10.0, 2.0);
let mut final_result = 0.0;

// Usamos `if let` para manejar el caso Some
// y asignar el valor a `final_result`
if let Some(value) = result {
final_result = value;
} else {
// Si es None, podemos manejar el error o asignar un valor por defecto
let error_message = "Error: No se pudo realizar la división".to_string();
eprintln!("{}", error_message);
}

// Ahora `final_result` contiene el valor final o un valor por defecto
}

.unwrap()

Similar al caso de Result, puedes usar .unwrap() para extraer el valor de Some(T), pero si el resultado es None, Rust causará un panic. Sin embargo, es útil en casos donde estás seguro de que no habrá None.

fn main() {
let result = divide(10.0, 2.0);

// Usamos `.unwrap()` para obtener el valor de Some,
// esto causará panic si es None
let value = result.unwrap(); // Si es Some, extrae el valor; si es None, panic

// Usamos `value` en el flujo de la aplicación
}

.unwrap_or()

Si deseas un valor por defecto cuando el Option es None, puedes usar .unwrap_or() y almacenar el resultado.

fn main() {
let result = divide(10.0, 0.0); // Intentamos dividir por cero, lo que genera un None

// Usamos `.unwrap_or()` para obtener un valor por defecto en caso de None
let final_result = result.unwrap_or(0.0); // Si es None, usamos 0.0 como valor por defecto

// Ahora `final_result` contiene el valor de la división o 0.0 si ocurrió un error
}

.map()

El método .map() te permite transformar el valor dentro de Some(T) si existe, sin tocar el None.


fn main() {
let result = divide(10.0, 2.0);

// Usamos `map` para aplicar una transformación si es Some
let transformed_result = result.map(|v| v * 2.0); // Multiplicamos el valor si es Some

// Si es None, asignamos un valor por defecto
let final_result = transformed_result.unwrap_or(0.0); // Si es None, usamos 0.0 como valor por defecto

// Ahora `final_result` contiene el resultado transformado o un valor por defecto
}

Almacenando y manejando None

Si necesitas manejar el None (por ejemplo, loguearlo o enviarlo como respuesta en una API), puedes extraerlo y realizar alguna acción con él.

fn main() {
let result = divide(10.0, 0.0); // Intentamos dividir por cero, lo que genera un None

// Extraemos el error si es None y almacenamos o gestionamos el error
let result_value = match result {
Some(value) => value.to_string(), // Si es Some, simplemente usamos el valor
None => {
let error_message = "No se pudo realizar la división".to_string();
// Aquí podrías loguear el error
eprintln!("{}", error_message);
"Error".to_string() // Guardamos el error como un mensaje o un valor por defecto
}
};

// Ahora `result_value` tiene el valor exitoso o un mensaje de error
}

Result<T, E>

  • Result<T, E> es una enumeración que representa la posibilidad de que una operación falle
  • Result<T, E> es un tipo genérico, lo que significa que puede contener cualquier tipo de valor.
enum Result<T, E> {
Ok(T),  // Devuelve un valor
Err(E), // Devuelve un error
}
fn main() {

fn division(numerador: f64, denominador: f64) -> Result<f64, String> {
if denominador == 0.0 {
Err("No se puede dividir por cero".to_string())
} else {
Ok(numerador / denominador)
}
}

match division(100.0, 2.0) {
  Ok(resultado) => println!("El resultado es: {}", resultado),
  Err(mensaje) => println!("Error: {}", mensaje),
  }
}

match

Aquí guardamos el valor de éxito (Ok(T)) en una variable, si existe.

fn main() {
let result = divide(10.0, 2.0); // Llamamos a la función

// Usamos `match` para manejar el caso de éxito o error
let value = match result {
Ok(v) => v, // Si es Ok, guardamos el valor en `value`
Err(e) => {
// Si es Err, guardamos el mensaje de error en `error_message`
let error_message = e;
// Aquí podrías hacer algo con el error, como devolverlo en una API o loguearlo
// Como ejemplo, asignamos el error a la variable `value` para continuar el flujo
eprintln!("Error: {}", error_message);
0.0 // Retornamos un valor por defecto para continuar
}
};

// Ahora `value` contiene el resultado de la operación o 0.0 si hubo error
let final_result = value;
// Aquí puedes utilizar `final_result` para más operaciones o retornar en una API
}

if let

Si solo te interesa manejar el valor exitoso (Ok(T)), puedes usar if let y almacenar el resultado en una variable.

fn main() {
let result = divide(10.0, 2.0);

let mut final_result = 0.0; // Inicializamos la variable para almacenar el resultado

// Usamos `if let` para manejar el caso Ok y asignar el valor a `final_result`
if let Ok(value) = result {
final_result = value; // Si es Ok, asignamos el valor a `final_result`
} else {
// Si es Err, podemos manejar el error o asignar un valor por defecto
let error_message = "Error: No se pudo realizar la división".to_string();
// Aquí podrías hacer algo con el error, como loguearlo
eprintln!("{}", error_message);
}

// Ahora `final_result` contiene el valor final o un valor por defecto
}

.map()

Si necesitas realizar una transformación al valor dentro de Ok(T) y almacenarlo, puedes usar .map(). Si es Err(E), puedes manejarlo como desees.

fn main() {
let result = divide(10.0, 2.0);

// Usamos `map` para transformar el valor de Ok y almacenarlo en una variable
let transformed_result = result.map(|value| value * 2.0); // Multiplicamos el valor si es Ok

// Si es Err, asignamos un valor por defecto
let final_result = transformed_result.unwrap_or(0.0); // Si es Err, usamos 0.0 como valor por defecto

// Ahora `final_result` contiene el resultado transformado o un valor por defecto
}

.unwrap_or()

Si deseas un valor por defecto cuando el Result es Err, puedes usar .unwrap_or() y almacenar el resultado.

fn main() {
let result = divide(10.0, 0.0); // Intentamos dividir por cero, lo que genera un error

// Usamos `.unwrap_or()` para obtener un valor por defecto en caso de error
let final_result = result.unwrap_or(0.0); // Si es Err, usamos 0.0 como valor por defecto

// Ahora `final_result` contiene el valor de la división o 0.0 si ocurrió un error
}

Almacenando y manejando errores con Err(E)

Si necesitas manejar el error y almacenarlo, puedes extraer el error de Err(E) y realizar alguna acción con él (por ejemplo, loguearlo o enviarlo a una API).

fn main() {
let result = divide(10.0, 0.0); // Intentamos dividir por cero, lo que genera un error

// Extraemos el error si es Err y almacenamos o gestionamos el error
let error_message = match result {
Ok(value) => {
// Si es Ok, simplemente usamos el valor
value.to_string()
}
Err(e) => {
// Si es Err, almacenamos el mensaje de error y podemos manejarlo
eprintln!("Error: {}", e);
e // Guardamos el error si queremos manipularlo después
}
};

// Ahora `error_message` tiene el valor exitoso o el error como mensaje
}