Pular para o conteúdo

Result: sucesso ou erro como valor

Nesta página

Result<T, E> é um enum com duas variantes: Result.Ok(valor) para sucesso e Result.Err(erro) para falha. Usar Result como tipo de retorno deixa o compilador exigir que o chamador lide com ambos os casos — nada é silenciado.

Atenção à pontuação: use ponto (.) para construirResult.Ok(v) — e dois-pontos duplos (::) para casar em matchResult::Ok(v).

O exemplo abaixo mostra como construir variantes, checar o estado e extrair o valor com segurança:

Construtores, is_ok / is_err, unwrap, unwrap_or e uma função que retorna Result.

01-result-basics.zolo
Playground
// Feature: Result — success or error as a value

// Syntax: `Result.Ok(v)` / `Result.Err(e)`

// When to use: functions that may fail in an expected way.


use std::Result

// `Result` is an enum with two variants:

//   - `Result.Ok(value)`   success

//   - `Result.Err(error)`  failure


let ok = Result.Ok(42)
let err = Result.Err("something went wrong")

// -- Check the variant -----------------------------------------

print(ok.is_ok())  // true

print(ok.is_err())  // false

print(err.is_ok())  // false

print(err.is_err())  // true


// -- Extract the value ----------------------------------------

print(ok.unwrap())  // 42 — panic if Err

print(err.unwrap_or(0))  // 0  — default if Err

print(err.unwrap_err())  // "something went wrong"


// -- Function that returns Result -----------------------------

fn divide(a: int, b: int) -> Result<int, str> {
  if b == 0 {
    return Result.Err("division by zero")
  }
  return Result.Ok(a / b)
}

let r1 = divide(10, 2)
let r2 = divide(10, 0)
print(r1.is_ok())  // true

print(r1.unwrap())  // 5

print(r2.is_err())  // true

print(r2.unwrap_err())  // division by zero


// -- Read with unwrap_or — provides a safe default ------------

print(divide(100, 4).unwrap_or(-1))  // 25

print(divide(100, 0).unwrap_or(-1))  // -1

Com match você trata os dois casos de forma exaustiva — o compilador rejeita código que esqueça um dos braços:

match como instrução e como expressão; bindings com nomes descritivos.

02-result-match.zolo
Playground
// Feature: Match on Result

// Syntax: `match r { Result::Ok(v) => ..., Result::Err(e) => ... }`

// When to use: handle success and failure exhaustively.


use std::Result

fn divide(a: int, b: int) -> Result<int, str> {
  if b == 0 {
    return Result.Err("division by zero")
  }
  return Result.Ok(a / b)
}

// -- Exhaustive match ------------------------------------------

fn describe(r: Result<int, str>) {
  match r {
    Result::Ok(v) => print("ok: {v}"),
    Result::Err(e) => print("error: {e}"),
  }
}

describe(divide(10, 2))
// expected: ok: 5

describe(divide(10, 0))

// expected: error: division by zero


// Note the match syntax: `Result::Ok` (with `::`), not `.`.

// To CONSTRUCT, use `Result.Ok(v)` (with `.`).


// -- Match as expression ---------------------------------------

fn format(r: Result<int, str>) -> str {
  return match r {
    Result::Ok(v) => "value = {v}",
    Result::Err(_) => "(failed)",
  }
}

print(format(divide(10, 2)))  // value = 5

print(format(divide(10, 0)))  // (failed)


// -- Bindings with different names -----------------------------

let r = divide(20, 4)
match r {
  Result::Ok(number) => print("computed {number}"),
  Result::Err(reason) => print("failed: {reason}"),
}
// expected: computed 5

Desafio

Adicione uma terceira chamada describe(divide(10, 10)) e verifique que o braço Ok imprime ok: 1. Em seguida, troque unwrap() por unwrap_or(99) em r2 — qual é a saída?

Buscar no Zolo

9 resultados

enespt-br