Skip to content
Snippets Groups Projects
title: Cours de programmation séquentielle
subtitle: Gestion d'erreurs
author: Orestis Malaspinas
sansfont: Sans Serif

Gestion d'erreurs

  • 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.

Panique!

panic!(){.rust}

  • Nous avons vu le macro panic!("texte"){.rust}.
  • Le programme s'arrête et affiche le "texte"{.rust}.
  • Utilisation:
    • Le programme ne doit pas continuer quoi qu'il arrive.

      
        fn elem(v: &[i32], i: usize) -> i32 {
        	if i >= v.len() {
        		panic!("Erreur fatale!");
        	}
        	// assert!(i < v.len(), "Erreur fatale!"); // ceci est équivalent
        	v[i]
        }
      
        fn main() {
        	let v = [1, 2, 3, 4];
        	elem(&v, 100);
        }
        
    • Avec l'appel RUST_BACKTRACE=1 on peut remonter la pile d'appels (debugging).

       	$ 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

  • On peut utiliser trois macros forts utiles.

:::::::::::::: {.columns} ::: {.column width="50%"}

  • assert!(cond, "Texte");{.rust}

fn main() {
    let num = 1;
    let denum = 0;

    assert!(denum != 0, "Le dénominateur doit être non nul.");
    let _total = num / denum;
}

::: ::: {.column width="50%"}

  • assert_eq!(lhs, rhs, "Texte");{.rust}

fn main() {
    let a = 1;
    let b = 0;

    assert_eq!(a, b, "A et b devraient être égales.");
}

::: ::::::::::::::

  • assert_ne!(lhs, rhs, "Texte");{.rust}

fn main() {
    let a = 1;
    let b = 0;

    assert_ne!(a, b, "A et b devraient être différentes.");
}

Options

  • Un type énuméré particulièrement utile est le type Option{.rust}

     enum Option<T> { // <T> est une notation pour un type générique
         Some(T),
         None,
     }
  • Type utilisé lorsque une valeur peut être "quelque chose" ou "rien" (ex: recherche d'un élément dans un tableau).

  • Exmple: la division

    
      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."),
          }
      }
      
  • Il est commun que des fonction retournent des Option{.rust}.

Résultat

  • Pour un traitement plus fin des erreurs l'enum

    
      enum Result<T, E> {
         Ok(T),
         Err(E),
      }
      
  • Contient le un élément de type T quand tout se passe bien et E pour l'erreur.

    
      	fn elem(v: &[i32], i: usize) -> Result<i32, &str> {
      		if i >= v.len() {
      			return Err("Erreur fatale!")
      		} 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(_) => println!("Mince ça a raté."),
      		}
      	}