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.
// 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
ecapturada pelocatchcontém o texto do pânico precedido pela localização no código (arquivo e linha) — não é apenas a string que você passou parapanic.
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.
// 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>.