Result

Nosso mecanismo primário para tratamento de erros em Rust é o enum Result, que vimos brevemente ao discutir tipos da biblioteca padrão.

use std::fs::File;
use std::io::Read;

fn main() {
    let file: Result<File, std::io::Error> = File::open("diary.txt");
    match file {
        Ok(mut file) => {
            let mut contents = String::new();
            if let Ok(bytes) = file.read_to_string(&mut contents) {
                println!("Querido diário: {contents} ({bytes} bytes)");
            } else {
                println!("Não foi possível ler o conteúdo do arquivo");
            }
        }
        Err(err) => {
            println!("Não foi possível abrir o diário: {err}");
        }
    }
}
This slide should take about 5 minutes.
  • Result tem duas variantes: Ok que contém o valor de sucesso, e Err que contém um valor de erro de algum tipo.

  • Se uma função pode ou não produzir um erro é codificado na assinatura de tipo da função, fazendo-a retornar um valor Result.

  • Assim como com Option, não há como esquecer de lidar com um erro: você não pode acessar nem o valor de sucesso nem o valor de erro sem primeiro corresponder a um padrão no Result para verificar qual variante você tem. Métodos como unwrap facilitam a escrita de código rápido e sujo que não faz um tratamento de erros robusto, mas significa que você sempre pode ver em seu código-fonte onde o tratamento de erros adequado está sendo ignorado.

Mais para Explorar

Pode ser útil comparar o tratamento de erros em Rust com convenções de tratamento de erros com as quais os alunos podem estar familiarizados de outras linguagens de programação.

Exceções

  • Muitas linguagens usam exceções, por exemplo, C++, Java, Python.

  • Na maioria das linguagens com exceções, se uma função pode ou não lançar uma exceção não é visível como parte de sua assinatura de tipo. Isso geralmente significa que você não pode dizer ao chamar uma função se ela pode lançar uma exceção ou não.

  • Exceções geralmente desmontam a pilha de chamadas, propagando-se para cima até que um bloco try seja alcançado. Um erro originado profundamente na pilha de chamadas pode impactar uma função não relacionada mais acima.

Números de Erro

  • Algumas linguagens têm funções que retornam um número de erro (ou algum outro valor de erro) separadamente do valor de retorno bem-sucedido da função. Exemplos incluem C e Go.

  • Dependendo da linguagem, pode ser possível esquecer de verificar o valor de erro, caso em que você pode estar acessando um valor de sucesso não inicializado ou de outra forma inválido.