Ferrugem - Tratamento de Erros

Em Rust, os erros podem ser classificados em duas categorias principais, conforme mostrado na tabela abaixo.

Sr. Não Nome e Descrição Uso
1

Recoverable

Erros que podem ser tratados

Resultado enum
2

UnRecoverable

Erros que não podem ser tratados

macro de pânico

Um erro recuperável é um erro que pode ser corrigido. Um programa pode tentar novamente a operação que falhou ou especificar um curso de ação alternativo ao encontrar um erro recuperável. Erros recuperáveis ​​não fazem com que um programa falhe abruptamente. Um exemplo de erro recuperável é o erro Arquivo não encontrado .

Erros irrecuperáveis ​​fazem com que um programa falhe abruptamente. Um programa não pode voltar ao seu estado normal se ocorrer um erro irrecuperável. Ele não pode repetir a operação com falha ou desfazer o erro. Um exemplo de erro irrecuperável é tentar acessar um local além do final de uma matriz.

Ao contrário de outras linguagens de programação, Rust não tem exceções. Ele retorna um resultado enum <T, E> para erros recuperáveis, enquanto chama opanicmacro se o programa encontrar um erro irrecuperável. A macro de pânico faz com que o programa seja encerrado abruptamente.

Macro de pânico e erros irrecuperáveis

pânico! macro permite que um programa termine imediatamente e forneça feedback ao chamador do programa. Deve ser usado quando um programa atinge um estado irrecuperável.

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

No exemplo acima, o programa será encerrado imediatamente quando encontrar o pânico! macro.

Resultado

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

Ilustração: pânico! macro

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

A saída é como mostrado abaixo -

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.

Um programa pode invocar o pânico! macro se as regras de negócios forem violadas, conforme mostrado no exemplo abaixo -

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");
}

O exemplo acima retorna um erro se o valor atribuído à variável for ímpar.

Resultado

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

Resultado Enum e erros recuperáveis

Resultado Enum - <T, E> pode ser usado para tratar erros recuperáveis. Possui duas variantes -OK e Err. T e E são parâmetros de tipo genérico. T representa o tipo de valor que será retornado em um caso de sucesso dentro da variante OK, e E representa o tipo de erro que será retornado em um caso de falha na variante Err.

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

Vamos entender isso com a ajuda de um exemplo -

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

O programa retorna OK (Arquivo) se o arquivo já existe e Err (Erro) se o arquivo não for encontrado.

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

Vamos agora ver como lidar com a variante Err.

O exemplo a seguir lida com um erro retornado ao abrir o arquivo usando o match declaração

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- O programa imprime o final do evento principal , embora o arquivo não tenha sido encontrado. Isso significa que o programa tratou os erros de maneira adequada.

Resultado

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

Ilustração

A função is_even retorna um erro se o número não for um número par. A função main () lida com esse erro.

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- Uma vez que a função principal lida com erros normalmente, o final da instrução principal é impresso.

Resultado

Error msg is NOT_AN_EVEN
end of main

desembrulhe () e espere ()

A biblioteca padrão contém alguns métodos auxiliares que ambas as enums - Result <T, E> e Option <T> implementam. Você pode usá-los para simplificar os casos de erro em que você realmente não espera que as coisas falhem. Em caso de sucesso de um método, a função "desembrulhar" é usada para extrair o resultado real.

Sr. Não Método Assinatura e Descrição
1 desembrulhar

unwrap(self): T

Espera-se estar Ok / Algum e retorna o valor contido em. Se forErr ou None em vez disso, causa pânico com o conteúdo do erro exibido.

2 Espero

expect(self, msg: &str): T

Comporta-se como desembrulhar, exceto que ele produz uma mensagem personalizada antes de entrar em pânico, além do conteúdo do erro.

desembrulhar()

A função unbrap () retorna o resultado real de uma operação bem-sucedida. Ele retorna um pânico com uma mensagem de erro padrão se uma operação falhar. Esta função é uma abreviatura para declaração de correspondência. Isso é mostrado no exemplo abaixo -

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 o código acima para passar um número ímpar para o is_even() função.

A função unbrap () entrará em pânico e retornará uma mensagem de erro padrão como mostrado abaixo

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

Espero()

O programa pode retornar uma mensagem de erro personalizada em caso de pânico. Isso é mostrado no seguinte exemplo -

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");
}

A função expect () é semelhante a unbrap (). A única diferença é que uma mensagem de erro personalizada pode ser exibida usando esperar.

Resultado

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.