Ce face panic!
panic! semnalează o eroare din care programul nu își poate reveni în mod normal: o greșeală de programare, o stare imposibilă. Afișează pe ieșirea de eroare thread 'main' panicked at fisier:linie:coloana: urmat de mesaj, eliberează valorile de pe stivă (apelează drop) și oprește firul. Dacă firul este main, programul se termină cu codul 101.
Multe operații dau panică intern: unwrap() pe None sau Err, indicele în afara unui vector, împărțirea întreagă la zero, depășirea unui întreg în modul debug. Variabila de mediu RUST_BACKTRACE=1 afișează și lanțul de apeluri care a dus la panică.
Pentru erori așteptate (fișier inexistent, date greșite de la utilizator) folosește Result, nu panic!: apelantul poate decide ce face. O panică dintr-un fir secundar nu oprește programul: join() returnează Err. std::panic::catch_unwind poate prinde o panică, dar nu este un mecanism de excepții pentru uz obișnuit.
Exemple
Exemplul 1: Panică pentru o stare imposibilă
Programul afișează primul calcul, apoi ajunge la o lună invalidă și se oprește. Mesajul conține fișierul, linia și coloana unde a fost apelat panic!. Numărul dintre paranteze identifică firul și diferă la fiecare rulare.
fn zile_in_luna(luna: u32) -> u32 {
match luna {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 => 28,
_ => panic!("luna {luna} nu există"),
}
}
fn main() {
println!("Aprilie are {} zile", zile_in_luna(4));
println!("Luna 13 are {} zile", zile_in_luna(13));
}
Rezultat (programul se oprește cu panică)
Aprilie are 30 zile
thread 'main' (14809654) panicked at main.rs:6:14:
luna 13 nu există
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Exemplul 2: Panica dintr-un fir secundar nu oprește programul
Un panic hook propriu înlocuiește mesajul implicit cu unul scurt. Firul care dă panică se oprește, dar main continuă: join() returnează Err, iar celălalt fir își termină treaba.
use std::panic;
use std::thread;
fn main() {
panic::set_hook(Box::new(|info| {
let mesaj = info.payload().downcast_ref::<String>().map(|s| s.as_str())
.or_else(|| info.payload().downcast_ref::<&str>().copied())
.unwrap_or("?");
println!(" (panică: {mesaj})");
}));
let bun = thread::spawn(|| 10 + 20);
let rau = thread::spawn(|| -> i32 { panic!("fișierul de configurare lipsește") });
println!("fir rău: {:?}", rau.join().is_err());
println!("fir bun: {:?}", bun.join());
println!("main continuă normal");
}
Rezultat
(panică: fișierul de configurare lipsește)
fir rău: true
fir bun: Ok(30)
main continuă normal
Greșeli frecvente
- Folosești
panic!(sauunwrap()) pentru erori obișnuite, ca un fișier care lipsește. Programul se oprește brusc; returnează unResultși lasă apelantul să decidă. - Folosești
catch_unwindca petry/catch. Nu toate panicile pot fi prinse (cupanic = "abort"înCargo.tomlprogramul se oprește imediat), iar codul devine greu de urmărit. - Dai panică într-un
dropîn timpul altei panici: programul este oprit imediat (abort), fără mesaj clar.
Comenzi înrudite
assert! și debug_assert!: Verifică o condiție la rulare și dă panică dacă este falsă. debug_assert! face verificarea doar în modul debug, nu și în release.unreachable!: Marchează un loc din cod la care execuția nu ar trebui să ajungă niciodată; dacă ajunge totuși, dă panică.todo! și unimplemented!: Țin locul unui cod nescris: programul se compilează, dar dacă se ajunge acolo, dă panică cu „not yet implemented”.operatorul ?: Pus după un Result sau Option: dă valoarea dacă totul e bine, altfel returnează imediat eroarea (sau None) din funcția curentă.eprintln! și eprint!: Ca println! și print!, dar scriu pe ieșirea de eroare (stderr), separată de rezultatul normal al programului.