Pular para o conteúdo

panic, try/catch e catch_panic

Nesta página

panic é para bugs e contratos quebrados — situações que não deveriam acontecer se o código estiver correto. Ao contrário de Result, um panic interrompe a execução imediatamente; não é um valor a propagar.

try / catch / finally permite capturar panics em uma fronteira controlada. finally executa sempre, com ou sem pânico:

try/catch/finally, try como expressão, panic com interpolação, try aninhado.

06-try-catch.zolo
Playground
// Feature: try / catch / finally

// Syntax: `try { ... } catch e { ... } finally { ... }`

// When to use: catch panics and ensure cleanup.


// -- Basic try / catch ----------------------------------------

try {
  panic("something went wrong!")
} catch e {
  print("caught!")
}

// expected: caught!

// (the variable `e` contains the message with the panic location info)


// -- try / catch / finally ------------------------------------

try {
  print("trying...")
  panic("oops")
} catch e {
  print("caught error")
} finally {
  print("cleanup always runs")
}

// expected:

// trying...

// caught error

// cleanup always runs


// finally runs even when there is NO panic.

try {
  print("ok")
} catch e {
  print("won't enter")
} finally {
  print("still runs")
}

// expected:

// ok

// still runs


// -- try as expression — returns a value ----------------------

let v = try { 42 } catch e { -1 }
print(v)  // 42


let f = try { panic("x"); 0 } catch e { 99 }
print(f)  // 99


// -- panic with interpolated message --------------------------

fn divide(a: int, b: int) -> int {
  if b == 0 {
    panic("Division by zero: {a} / {b}")
  }
  return a / b
}

let safe = try { divide(10, 0) } catch e { -1 }
print(safe)  // -1


print(try { divide(9, 3) } catch e { -1 })

// expected: 3 (exact division)


// -- Nested try/catch -----------------------------------------

try {
  try {
    panic("inner")
  } catch e {
    print("inner caught")
    panic("re-thrown")
  }
} catch e {
  print("outer caught")
}
// expected:

// inner caught

// outer caught

A variável e capturada pelo catch contém o texto do pânico precedido pela localização no código (arquivo e linha) — não é apenas a string que você passou para panic.

Quando precisar tratar uma função que pode panicar como se fosse Result, use catch_panic. Ele retorna um objeto com .ok (bool) e .value (o retorno em caso de sucesso). Para passar argumentos, envolva em uma closure:

panic, catch_panic com e sem closure, Result.from_pcall para converter panic em Result.

08-panic-and-catch.zolo
Playground
// Feature: panic and catch_panic

// Syntax: `panic("msg")`, `catch_panic(fn, args...)`

// When to use: non-recoverable errors (panic), safe wrapping (catch_panic).


use std::Result

// -- panic — interrupts execution ------------------------------

// When an invariant is violated and there's no reasonable recovery:

fn must_be_positive(n: int) -> int {
  if n < 0 {
    panic("n must be positive, got {n}")
  }
  return n
}

print(must_be_positive(5))  // 5


// Without catching, panic terminates the program. To catch:

let safe = try { must_be_positive(-3) } catch e { -1 }
print(safe)  // -1


// -- catch_panic — wraps a function call -----------------------

// Useful when you want to call an external function that may

// panic and treat the result as data.


fn risky() -> int {
  panic("boom")
  return 0
}

let res = catch_panic(risky)
if res.ok {
  print("value: {res.value}")
} else {
  print("caught panic")
}

// expected: caught panic


// Success:

fn safe_fn() -> int {
  return 42
}

let r2 = catch_panic(safe_fn)
if r2.ok {
  print("value: {r2.value}")
} else {
  print("caught panic")
}

// expected: value: 42


// -- catch_panic with a closure capturing arguments -----------

// To pass arguments to a function under catch_panic, wrap it in

// a zero-parameter closure.

fn divide_panic(a: int, b: int) -> int {
  if b == 0 {
    panic("division by zero")
  }
  return a / b
}

let ok = catch_panic(|| divide_panic(10, 2))
let err = catch_panic(|| divide_panic(10, 0))

print(ok.ok)  // true

print(ok.value)  // 5

print(err.ok)  // false


// -- Result.from_pcall — converts panic into Result -----------

fn require_positive(n: int) -> int {
  if n < 0 {
    panic("negative")
  }
  return n * 2
}

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

describe(Result::from_pcall(require_positive, 5))
// expected: ok: 10

describe(Result::from_pcall(require_positive, -1))
// expected: error caught

Regra prática: capture panics apenas em fronteiras (topo da aplicação, testes, wrappers de bibliotecas externas). Dentro da lógica de negócio, prefira Result<T, E>.

Buscar no Zolo

9 resultados

enespt-br