Da trilha de Rust Este conceito ainda não saiu como card do dia. ir para o card de hoje

Rust Erros Intermediário

Result e o operador ?

Em Rust, o tratamento de erros é explícito: funções que podem falhar retornam Result<T, E>, uma enumeração com as variantes Ok(T) para sucesso e Err(E) para falha. Isso obriga o programador a lidar com os dois casos, evitando exceções não verificadas.

O operador ? simplifica a propagação de erros: se o valor for Ok, ele extrai o conteúdo; se for Err, ele retorna o erro imediatamente da função atual. Isso mantém o código limpo, sem vários match aninhados.

Para usar ? em uma função, o tipo de retorno dela deve ser compatível com o erro propagado. Erros customizados podem ser criados implementando std::error::Error e a conversão From para permitir que ? converta automaticamente entre tipos de erro.

Neste card, você verá como definir seus próprios erros, implementar From e usar ? para escrever código robusto e legível.

Pontos-chave

  • Result<T, E> tem duas variantes: Ok(T) para sucesso e Err(E) para erro.
  • O operador ? extrai o valor de Ok ou retorna o Err imediatamente.
  • ? só pode ser usado em funções cujo retorno é Result (ou Option).
  • Erros customizados implementam std::error::Error e Display.
  • A conversão From permite que ? transforme um erro em outro automaticamente.
resultado.rs
use std::fmt;
use std::num::ParseIntError;

// Erro customizado
#[derive(Debug)]
enum MeuErro {
    Parse(ParseIntError),
    Negativo,
}

// Permite converter ParseIntError em MeuErro automaticamente
impl From<ParseIntError> for MeuErro {
    fn from(e: ParseIntError) -> Self {
        MeuErro::Parse(e)
    }
}

impl fmt::Display for MeuErro {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            MeuErro::Parse(e) => write!(f, "erro de parse: {}", e),
            MeuErro::Negativo => write!(f, "número negativo não permitido"),
        }
    }
}

// Função que usa ? para propagar erros
fn dobra_numero(s: &str) -> Result<i32, MeuErro> {
    let n: i32 = s.parse()?; // converte ParseIntError em MeuErro via From
    if n < 0 {
        return Err(MeuErro::Negativo);
    }
    Ok(n * 2)
}

fn main() {
    println!("{:?}", dobra_numero("21"));  // Ok(42)
    println!("{:?}", dobra_numero("-5"));  // Err(Negativo)
    println!("{:?}", dobra_numero("abc")); // Err(Parse(...))
}

Exercícios

  1. 1
    Fácil

    Propagando erro de parse

    Escreva uma função soma_strings que recebe duas strings, converte cada uma para i32 e retorna a soma. Use o operador ? para propagar erros de conversão. O retorno deve ser Result<i32, std::num::ParseIntError>.

    Resolver
  2. 2
    Médio

    Erro customizado com From

    Crie um erro customizado MeuErro que represente falhas de conversão e valores negativos. Implemente From<ParseIntError> para permitir o uso de ?. Depois, escreva uma função raiz_quadrada que recebe uma string, converte para f64 e retorna a raiz quadrada; se o número for negativo, retorne Err(MeuErro::Negativo).

    Resolver
  3. 3
    Desafio

    Múltiplos erros e uso de ? em cadeia

    Crie um sistema de validação de idade e email. Defina um enum ErroCadastro com variantes para idade inválida (IdadeInvalida), email sem @ (EmailInvalido) e erro de conversão (Parse). Implemente From<ParseIntError>. Escreva uma função cadastrar que recebe idade como string e email como string, converte a idade, valida se é >= 18 e se o email contém @. Use ? para propagar todos os erros. Retorne Ok(()) se tudo estiver correto.

    Resolver

Continue estudando