Desafio Rust

Calculadora com expressões e retorno implícito

Enunciado

Crie uma função calcula(a: i32, b: i32, op: char) -> Result<i32, String> que realize operações básicas (+ - * /) e retorne Ok(resultado) ou Err(mensagem) em caso de operador inválido ou divisão por zero. Use blocos como expressões e retorno implícito. No main, itere sobre uma lista de operações e imprima o resultado ou a mensagem de erro.

Requisitos

  • A função deve se chamar calcula e aceitar i32, i32 e char.
  • Deve retornar Result<i32, String>.
  • Deve tratar divisão por zero com Err("Divisão por zero".to_string()).
  • Deve tratar operador inválido com Err(format!("Operador inválido: {}", op)).
  • O main deve imprimir os resultados no formato a op b = resultado ou a op b = Erro: mensagem.

Código inicial

fn calcula(a: i32, b: i32, op: char) -> Result<i32, String> {
    // escreva seu código aqui
}

fn main() {
    let operacoes = [(10, 5, '+'), (10, 0, '/'), (7, 3, '*'), (8, 2, '%')];
    for &(a, b, op) in &operacoes {
        match calcula(a, b, op) {
            Ok(res) => println!("{} {} {} = {}", a, op, b, res),
            Err(e) => println!("{} {} {} = Erro: {}", a, op, b, e),
        }
    }
}

Saída esperada

10 + 5 = 15
10 / 0 = Erro: Divisão por zero
7 * 3 = 21
8 % 2 = Erro: Operador inválido: %
Ver dica

Use match op para selecionar a operação. Cada braço pode ser um bloco que retorna Ok(...) ou Err(...). Lembre-se de verificar divisão por zero antes de dividir.

Mostrar solução
fn calcula(a: i32, b: i32, op: char) -> Result<i32, String> {
    match op {
        '+' => Ok(a + b),
        '-' => Ok(a - b),
        '*' => Ok(a * b),
        '/' => {
            if b == 0 {
                Err("Divisão por zero".to_string())
            } else {
                Ok(a / b)
            }
        }
        _ => Err(format!("Operador inválido: {}", op)),
    }
}

fn main() {
    let operacoes = [(10, 5, '+'), (10, 0, '/'), (7, 3, '*'), (8, 2, '%')];
    for &(a, b, op) in &operacoes {
        match calcula(a, b, op) {
            Ok(res) => println!("{} {} {} = {}", a, op, b, res),
            Err(e) => println!("{} {} {} = Erro: {}", a, op, b, e),
        }
    }
}

Passo a passo

  1. A função calcula recebe dois i32 e um char, retornando Result<i32, String>.
  2. Usamos match op para comparar o caractere com cada operador suportado.
  3. Para '+', '-', '*', retornamos diretamente Ok com o resultado da operação.
  4. Para '/', verificamos se b == 0; se sim, retornamos Err com a mensagem; senão, Ok(a / b).
  5. O braço _ captura qualquer outro caractere e retorna Err com format!.
  6. Cada braço do match é uma expressão; o valor do braço escolhido é o retorno implícito da função.
  7. Em main, iteramos sobre um array de tuplas e usamos match no Result para imprimir o sucesso ou o erro.

Por que funciona

O match é uma expressão que avalia para um valor. Como todos os braços retornam Result<i32, String>, o tipo do match é esse Result, que se torna o retorno implícito da função. O uso de blocos dentro do braço '/' permite lógica condicional sem return explícito. O retorno implícito mantém o código conciso e idiomático.

Erros comuns

  • Esquecer o braço _ no match: o compilador exige exaustividade e dá erro.
  • Tentar dividir por zero sem verificar: panic em tempo de execução.
  • Retornar Ok(a / b) diretamente no braço '/' sem checar b == 0: panic.
  • Usar return dentro dos braços: funciona, mas não é necessário e foge do estilo.

Outra forma de resolver

Usar if/else if em vez de match:

fn calcula(a: i32, b: i32, op: char) -> Result<i32, String> {
    if op == '+' { Ok(a + b) }
    else if op == '-' { Ok(a - b) }
    else if op == '*' { Ok(a * b) }
    else if op == '/' {
        if b == 0 { Err("Divisão por zero".to_string()) }
        else { Ok(a / b) }
    } else {
        Err(format!("Operador inválido: {}", op))
    }
}

match é preferível por ser mais legível e exaustivo.

Saída esperada

10 + 5 = 15
10 / 0 = Erro: Divisão por zero
7 * 3 = 21
8 % 2 = Erro: Operador inválido: %