Home
# Gestion d'erreurs --- ## Les différents types d'erreur - Il est important de pouvoir gérer trois cas: - La panique totale (erreur fatale du programme). - L'erreur dont on peut se remettre. - Un résultat qui peut contenir une valeur ou pas. --- ## `panic!()` ```rust should_panic [2-4|] fn elem(v: &[i32], i: usize) -> i32 { if i >= v.len() { panic!("Erreur fatale!"); } v[i] } fn main() { let v = [1, 2, 3, 4]; elem(&v, 100); } ``` --- ## Debugging ```sh $ RUST_BACKTRACE=1 cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.01s Running `target/debug/ma_librairie` thread 'main' panicked at 'Erreur fatale!', src/main.rs:5:3 stack backtrace: 0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49 1: std::sys_common::backtrace::print at libstd/sys_common/backtrace.rs:71 at libstd/sys_common/backtrace.rs:59 2: std::panicking::default_hook::{{closure}} at libstd/panicking.rs:211 3: std::panicking::default_hook at libstd/panicking.rs:227 4: std::panicking::rust_panic_with_hook at libstd/panicking.rs:477 5: std::panicking::begin_panic at /checkout/src/libstd/panicking.rs:411 6: ma_librairie::elem at src/main.rs:5 7: ma_librairie::main at src/main.rs:12 8: std::rt::lang_start::{{closure}} at /checkout/src/libstd/rt.rs:74 9: std::panicking::try::do_call at libstd/rt.rs:59 at libstd/panicking.rs:310 10: __rust_maybe_catch_panic at libpanic_unwind/lib.rs:102 11: std::rt::lang_start_internal at libstd/panicking.rs:289 at libstd/panic.rs:392 at libstd/rt.rs:58 12: std::rt::lang_start at /checkout/src/libstd/rt.rs:74 13: main 14: __libc_start_main 15: _start ``` --- ## Asserts ```rust should_panic [4,6,7|] fn main() { let num = 1; let denum = 0; assert!(denum != 0, "Le dénominateur doit être non nul."); let _total = num / denum; assert_eq!(num, denum, "num et denum devraient être égales."); assert_ne!(num, denum, "num et denum devraient être différentes."); } ``` --- ## Options ```rust enum Option
{ //
est une notation pour un type générique Some(T), None, } ``` - Type énuméré générique, `Some` encapsule un `T`, `None` un "rien". --- ## Options: exemple ```rust [4-9|10-13|] fn main() { let num = 1; let denum = 4; let div = if denum == 0 { None } else { Some(num / denum) }; match div { Some(d) => println!("{} divisé par {} donne {}", num, denum, d), None => println!("Cette division n'existe pas."), } } ``` --- ## Options: `if let` ```rust [1-7|11-15|] fn div(num: i32, denum: i32) -> Option
{ if denum == 0 { None } else { Some(num / denum) } } fn main() { let num = 1; let denum = 4; if let Some(res) = div(num, denum) { println!("{num} / {denum} = {res}"); } else { println!("Une division par zéro est impossible."); } } ``` --- ## Options: `unwrap()` ```rust should_panic [11|] fn div(num: i32, denum: i32) -> Option
{ if denum == 0 { None } else { Some(num / denum) } } fn main() { let num = 1; let denum = 0; let res = div(num, denum).unwrap(); // panique! println!("{num} / {denum} = {res}"); } ``` --- ## Results ```rust enum Result
{ Ok(T), Err(E), } ``` - Deux types génériques `T` (réussite) et `E` (erreur). --- ## Exemple ```rust [1-7|10-13|] fn elem(v: &[i32], i: usize) -> Result
{ if i >= v.len() { Err("L'index est trop grand!") } else { Ok(v[i]) } } fn main() { let v = [1, 2, 3, 4]; match elem(&v, 100) { Ok(i) => println!("L'élément est {}", i), Err(e) => println!("Mince ça a raté car: {}.", e), } } ``` --- ## `unwrap()` ```rust should_panic [10|] fn elem(v: &[i32], i: usize) -> Result
{ if i >= v.len() { return Err("L'index est trop grand!") } else { Ok(v[i]) } } fn main() { let v = [1, 2, 3, 4]; let res = elem(&v, 100).unwrap(); println!("L'élément est {}", res); } ```