---
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.
		<pre><code data-trim="hljs rust" class="lang-rust">
		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);
		}
	    </code></pre>
	- 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}

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let num = 1;
    let denum = 0;

    assert!(denum != 0, "Le dénominateur doit être non nul.");
    let _total = num / denum;
}
</code></pre>
:::
::: {.column width="50%"}
- `assert_eq!(lhs, rhs, "Texte");`{.rust}

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let a = 1;
    let b = 0;

    assert_eq!(a, b, "A et b devraient être égales.");
}
</code></pre>
:::
::::::::::::::

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

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let a = 1;
    let b = 0;

    assert_ne!(a, b, "A et b devraient être différentes.");
}
</code></pre>


# Options

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

	```{.lang-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

	<pre><code data-trim="hljs rust" class="lang-rust">
	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."),
	    }
	}
	</code></pre>

- Il est commun que des fonction retournent des `Option`{.rust}.

# Résultat

## Lorsqu'on peut commettre des erreurs non-fatales

- Pour un traitement plus fin des erreurs l'enum

	<pre><code data-trim="hljs rust">
	enum Result&lt;T, E&gt; {
	   Ok(T),
	   Err(E),
	}
	</code></pre> 

- Contient le un élément de type `T` quand tout se passe bien et `E` pour l'erreur.

	<pre><code data-trim="hljs rust" class="lang-rust">
		fn elem(v: &[i32], i: usize) -> Result&lt;i32, &str&gt; {
		  if i >= v.len() {
		      return 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(error) => panic!("The problem is {:?}", error),
		      Err(_) => println!("Mince ça a raté."),
		  }
		}
    </code></pre> 
