Ce face panic::catch_unwind
catch_unwind apelează funcția dată. Dacă funcția se termină normal, returnează Ok(rezultat). Dacă funcția intră în panică, panica este oprită aici și primești Err(încărcătura), iar programul continuă.
Nu este un mecanism de tratare a erorilor obișnuite (pentru asta există Result). Se folosește la granițe: un server care nu vrea să se oprească din cauza unei cereri, cod apelat din C, rularea unor pluginuri. Mesajul panicii este tot afișat pe ecran de „hook”-ul implicit; îl poți schimba cu panic::set_hook.
Funcționează doar când panica face unwinding (comportamentul implicit). Cu panic = "abort" în Cargo.toml, programul se oprește oricum.
Parametri
| Parametru | Descriere |
|---|---|
f |
Funcția (de obicei un closure) rulată protejat. |
Ce returnează
Ok(R) dacă funcția s-a terminat normal; Err(Box<dyn Any + Send>) cu încărcătura panicii (de obicei un &str sau un String).
Exemple
Exemplul 1: Programul continuă după panică
Am înlocuit hook-ul de panică cu unul care afișează doar mesajul, pe o singură linie. Din încărcătură scoatem textul cu downcast_ref.
use std::panic;
fn proceseaza(comanda: u32) -> u32 {
if comanda == 2 {
panic!("comanda {comanda} are date corupte");
}
comanda * 100
}
fn main() {
panic::set_hook(Box::new(|info| {
println!(" [hook] panică: {}", info.payload_as_str().unwrap_or("?"));
}));
for c in 1..=3 {
let r = panic::catch_unwind(|| proceseaza(c));
match r {
Ok(v) => println!("comanda {c}: OK, {v} lei"),
Err(incarcatura) => {
let mesaj = incarcatura
.downcast_ref::<String>()
.map(String::as_str)
.or_else(|| incarcatura.downcast_ref::<&str>().copied())
.unwrap_or("necunoscut");
println!("comanda {c}: eșuată ({mesaj})");
}
}
}
println!("Programul a ajuns la final.");
}
Rezultat
comanda 1: OK, 100 lei
[hook] panică: comanda 2 are date corupte
comanda 2: eșuată (comanda 2 are date corupte)
comanda 3: OK, 300 lei
Programul a ajuns la final.
Exemplul 2: Fără hook propriu
Hook-ul implicit afișează mesajul obișnuit de panică (pe ieșirea de eroare), dar programul merge mai departe. Numărul firului diferă la fiecare rulare.
use std::panic;
fn main() {
let r = panic::catch_unwind(|| {
let v = [1, 2, 3];
let i = v.len() + 4;
v[i]
});
println!("prins: {}", r.is_err());
println!("Programul continuă.");
}
Rezultat posibil (diferă la fiecare rulare)
thread 'main' (52011) panicked at src/main.rs:7:9:
index out of bounds: the len is 3 but the index is 7
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
prins: true
Programul continuă.
Greșeli frecvente
- Folosești
catch_unwindca pe untry/catchpentru erori obișnuite. În Rust, erorile așteptate se returnează cuResult. - Prinzi o panică și continui să folosești datele pe care funcția le modifica: pot fi rămas pe jumătate actualizate. De aceea închiderea trebuie să fie
UnwindSafe; pentru referințe mutabile compilatorul cereAssertUnwindSafe. - Te aștepți să prinzi o panică atunci când proiectul este compilat cu
panic = "abort": în acest caz programul se oprește imediat.
Comenzi înrudite
Option::unwrap: Scoate valoarea din Some; pentru None programul se oprește cu panică. expect face la fel, cu mesajul tău.Result::unwrap: Scoate valoarea din Ok; pentru Err oprește programul cu panică. unwrap_err face invers: scoate eroarea.process::exit: Oprește imediat programul cu codul de ieșire dat (0 = succes, altceva = eroare), fără să mai ruleze restul codului.thread::spawn: Pornește un fir de execuție nou care rulează funcția dată; join() așteaptă terminarea lui și îi dă rezultatul.