Óxido - Manejo de errores

En Rust, los errores se pueden clasificar en dos categorías principales, como se muestra en la siguiente tabla.

No Señor Nombre y descripción Uso
1

Recoverable

Errores que pueden manejarse

Resultado enum
2

UnRecoverable

Errores que no se pueden manejar

macro de pánico

Un error recuperable es un error que se puede corregir. Un programa puede volver a intentar la operación fallida o especificar un curso de acción alternativo cuando encuentra un error recuperable. Los errores recuperables no hacen que un programa falle de forma abrupta. Un ejemplo de un error recuperable es el error de archivo no encontrado .

Los errores irrecuperables hacen que un programa falle abruptamente. Un programa no puede volver a su estado normal si ocurre un error irrecuperable. No puede volver a intentar la operación fallida o deshacer el error. Un ejemplo de un error irrecuperable es intentar acceder a una ubicación más allá del final de una matriz.

A diferencia de otros lenguajes de programación, Rust no tiene excepciones. Devuelve una enumeración Result <T, E> para errores recuperables, mientras que llama alpanicmacro si el programa encuentra un error irrecuperable. La macro de pánico hace que el programa se cierre abruptamente.

Macro de pánico y errores irrecuperables

¡pánico! macro permite que un programa finalice inmediatamente y proporcione información a la persona que llama del programa. Debe usarse cuando un programa alcanza un estado irrecuperable.

fn main() {
   panic!("Hello");
   println!("End of main"); //unreachable statement
}

En el ejemplo anterior, el programa terminará inmediatamente cuando encuentre el pánico. macro.

Salida

thread 'main' panicked at 'Hello', main.rs:3

Ilustración: ¡pánico! macro

fn main() {
   let a = [10,20,30];
   a[10]; //invokes a panic since index 10 cannot be reached
}

La salida es como se muestra a continuación:

warning: this expression will panic at run-time
--> main.rs:4:4
  |
4 | a[10];
  | ^^^^^ index out of bounds: the len is 3 but the index is 10

$main
thread 'main' panicked at 'index out of bounds: the len 
is 3 but the index is 10', main.rs:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

¡Un programa puede provocar el pánico! macro si se infringen las reglas de negocio como se muestra en el ejemplo siguiente:

fn main() {
   let no = 13; 
   //try with odd and even
   if no%2 == 0 {
      println!("Thank you , number is even");
   } else {
      panic!("NOT_AN_EVEN"); 
   }
   println!("End of main");
}

El ejemplo anterior devuelve un error si el valor asignado a la variable es impar.

Salida

thread 'main' panicked at 'NOT_AN_EVEN', main.rs:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Enumeración de resultados y errores recuperables

Resultado de enumeración: <T, E> se puede usar para manejar errores recuperables. Tiene dos variantes:OK y Err. T y E son parámetros de tipo genérico. T representa el tipo de valor que se devolverá en caso de éxito dentro de la variante OK, y E representa el tipo de error que se devolverá en caso de falla dentro de la variante Err.

enum Result<T,E> {
   OK(T),
   Err(E)
}

Entendamos esto con la ayuda de un ejemplo:

use std::fs::File;
fn main() {
   let f = File::open("main.jpg"); 
   //this file does not exist
   println!("{:?}",f);
}

El programa devuelve OK (Archivo) si el archivo ya existe y Err (Error) si no se encuentra el archivo.

Err(Error { repr: Os { code: 2, message: "No such file or directory" } })

Veamos ahora cómo manejar la variante Err.

El siguiente ejemplo maneja un error devuelto al abrir un archivo usando el match declaración

use std::fs::File;
fn main() {
   let f = File::open("main.jpg");   // main.jpg doesn't exist
   match f {
      Ok(f)=> {
         println!("file found {:?}",f);
      },
      Err(e)=> {
         println!("file not found \n{:?}",e);   //handled error
      }
   }
   println!("end of main");
}

NOTE- El programa imprime el final del evento principal aunque no se encontró el archivo. Esto significa que el programa ha manejado el error correctamente.

Salida

file not found
Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }
end of main

Ilustración

La función is_even devuelve un error si el número no es par. La función main () maneja este error.

fn main(){
   let result = is_even(13);
   match result {
      Ok(d)=>{
         println!("no is even {}",d);
      },
      Err(msg)=>{
         println!("Error msg is {}",msg);
      }
   }
   println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
   if no%2==0 {
      return Ok(true);
   } else {
      return Err("NOT_AN_EVEN".to_string());
   }
}

NOTE- Dado que la función principal maneja correctamente los errores, se imprime el final de la declaración principal .

Salida

Error msg is NOT_AN_EVEN
end of main

desenvolver () y esperar ()

La biblioteca estándar contiene un par de métodos auxiliares que implementan ambas enumeraciones: Result <T, E> y Option <T> . Puede usarlos para simplificar los casos de error en los que realmente no espera que las cosas fallen. En caso de éxito de un método, la función "desenvolver" se utiliza para extraer el resultado real.

No Señor Método Firma y descripción
1 desenvolver

unwrap(self): T

Espera que self sea Ok / Some y devuelve el valor que contiene. Si esto esErr o None en cambio, genera pánico con el contenido del error mostrado.

2 esperar

expect(self, msg: &str): T

Se comporta como desenvolver, excepto que genera un mensaje personalizado antes de entrar en pánico además del contenido del error.

desenvolver()

La función desenvolver () devuelve el resultado real de una operación. Devuelve un pánico con un mensaje de error predeterminado si falla una operación. Esta función es una abreviatura de la declaración de coincidencia. Esto se muestra en el siguiente ejemplo:

fn main(){
   let result = is_even(10).unwrap();
   println!("result is {}",result);
   println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
   if no%2==0 {
      return Ok(true);
   } else {
      return Err("NOT_AN_EVEN".to_string());
   }
}
result is true
end of main

Modifique el código anterior para pasar un número impar al is_even() función.

La función de desenvolver () entrará en pánico y devolverá un mensaje de error predeterminado como se muestra a continuación

thread 'main' panicked at 'called `Result::unwrap()` on 
an `Err` value: "NOT_AN_EVEN"', libcore\result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace

esperar()

El programa puede devolver un mensaje de error personalizado en caso de pánico. Esto se muestra en el siguiente ejemplo:

use std::fs::File;
fn main(){
   let f = File::open("pqr.txt").expect("File not able to open");
   //file does not exist
   println!("end of main");
}

La función esperar () es similar a desenvolver (). La única diferencia es que se puede mostrar un mensaje de error personalizado usando esperar.

Salida

thread 'main' panicked at 'File not able to open: Error { repr: Os 
{ code: 2, message: "No such file or directory" } }', src/libcore/result.rs:860
note: Run with `RUST_BACKTRACE=1` for a backtrace.