Skip to content
Snippets Groups Projects
Commit 8b128d10 authored by orestis.malaspin's avatar orestis.malaspin
Browse files

maj et nettoyage

parent 5c5ef885
Branches
No related tags found
1 merge request!68maj et nettoyage
Showing with 177 additions and 174 deletions
......@@ -81,6 +81,7 @@ deploy:book:
stage: deploy
only:
- main
- merge_request
script:
- cd book
- mdbook build
......@@ -90,6 +91,7 @@ deploy:slides:
stage: deploy
only:
- main
- merge_request
script:
- cd slides
- ./build_slides.sh
......
......@@ -6,13 +6,13 @@
- [] Lundi matin (9h-10h15, 10h45-12h):
- Vérification install, et Hello world.
- part00 à part01
- bases1 à bases2
- [] Lundi après-midi (13h-14h15, 14h45-16h):
- part02
- bases2
- [] Mardi matin (9h-10h15, 10h45-12h):
- part03-part04
- gen_types_composes - propriete
- [] Mardi après-midi (13h-14h15, 14h45-16h):
- part05-part06
- modules_visibilite - tooling
- [] Mercredi matin (9h-10h15, 10h45-12h):
- Gestion d'erreurs
- Closures
......@@ -30,7 +30,7 @@
# Soir
Lundi (17h-21h): Vérification install, intro, part00, part01, part02
Mardi (17h-21h): part03 & part04
Lundi (17h-21h): Vérification install, intro, bases1, bases2
Mardi (17h-21h): gen_types_composes & propriete
Mercredi (17h-21h): part 05 & part 06
Jeudi (17h-21h): Gestion d'erreurs, Lambda, Collections & Itérateurs
\ No newline at end of file
Jeudi (17h-21h): Gestion d'erreurs, Lambda, Collections & Itérateurs
......@@ -4,6 +4,11 @@ Le but de ce projet est de créer un cours de 5 séances de 2h de théorie avec
L'objectif du cours est de se familiariser avec le langage de programmation Rust tout en faisant une
introduction à différents concepts avancés de programmation orientée objet et de programmation fonctionnelle.
Le dbook et les slides du cours se trouvent sur les liens:
- [Book](https://malaspinas.academy/rust-101/book/)
- [SLides](https://malaspinas.academy/rust-101/slides/)
## Contexte
Les élèves ont suivi un cours de `C` pendant un an et ont donc des notions de base sur les structures de contrôle,
......@@ -180,26 +185,19 @@ simple que tout le monde peut comprendre. On pourra ainsi comparer l'implémenta
Le cours théorique est découpé comme suit:
0. Installation, tooling, Hello World.
0. Installation, Hello World.
1. Introduction à la syntaxe (structures de contrôle et types de base aka tous ceux qui sont Copy).
- variables immutables, variables mutables.
- références et références mutables.
- compilateur et lecture des messages
- tuples?
2. Types avancés (enum) et pattern matching.
- enum,
- struct,
3. Généricité et traits (Clone, Copy p.ex.).
4. Ownership, Borrowing.
5. Modules et visibilité.
6. Tests, documentation, outils variés (rustfmt, clippy, etc).
7. Gestion d'erreurs (Option, Result).
8. Closures (Fonctions anonymes)
9. Collections (Vec, String, HashMap)
9. Collections (Vec, String)
10. Itérateurs
11. Smart pointeurs (Rc principalement) et mutabilité intérieure.
11. Smart pointeurs.
12. CLI, I/O.
13. Unsafe Rust, Box, etc.
14. FFI
13. Unsafe Rust.
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />Ce(tte) œuvre est mise à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>.
......@@ -19,12 +19,11 @@ enable = true
[output.linkcheck]
# Should we check links on the internet? Enabling this option adds a
# non-negligible performance impact
follow-web-links = true
follow-web-links = false
# How should warnings be treated?
#
# - "warn" will emit warning messages
# - "error" treats all warnings as errors, failing the linkcheck
# - "ignore" will ignore warnings, suppressing diagnostic messages and allowing
# the linkcheck to continuing
warning-policy = "error"
warning-policy = "warn"
......@@ -2,17 +2,17 @@
[Introduction](introduction.md)
- [Les bases du Rust 1](./part00.md)
- [Les bases du Rust 2](./part01.md)
- [Les types avancés](./part02.md)
- [La généricité et des types composés](./part03.md)
- [La propriété](./part04.md)
- [Modules et visibilité](./part05.md)
- [Les petits trucs sympas qui aident au développement](./part06.md)
- [La gestion des erreurs en Rust](./part07.md)
- [Les closures](./part08.md)
- [Les itérateurs](./part10.md)
- [Les bases du Rust 1](./bases1.md)
- [Les bases du Rust 2](./bases2.md)
- [Les types avancés](./types_avances.md)
- [La généricité et des types composés](./gen_types_composes.md)
- [La propriété](./propriete.md)
- [Modules et visibilité](./modules_visibilite.md)
- [Les petits trucs sympas qui aident au développement](./tooling.md)
- [La gestion des erreurs en Rust](./gestion_erreurs.md)
- [Les closures](./closures.md)
- [Les itérateurs](./iterateurs.md)
- [Les collections](./collections.md)
- [Lifetimes](./lifetimes.md)
- [CLI](./cli.md)
- [Unsafe](./part12.md)
- [Unsafe](./unsafe.md)
# Discussion du code `part00`
# Discussion du code `bases1`
## Concepts
......
File moved
......@@ -33,7 +33,7 @@ Vous pouvez trouver plus d'informations aux liens suivants:
## L'interface à la ligne de commande et l'utilisation de librairies externes
Dans cette section nous allons voir une façon différente
de lire la ligne de commande (par rapport à ce que nous avons fait dans la [partie 07](part07.md)).
de lire la ligne de commande (par rapport à ce que nous avons fait dans la [partie 07](gestion_erreurs.md)).
Cette façon de faire est trop complexe pour construire une vraie application et
rajouterait beaucoup d'efforts à chaque fois qu'on veut en reconstruire une:
......@@ -51,7 +51,7 @@ clap = { version = "4.4.0", features = ["derive"] }
```
sous l'entrée `[dependecies]`.
2. Utiliser l'outil `cargo` qui le fait pour nous
1. Utiliser l'outil `cargo` qui le fait pour nous
```bash
cargo add clap --features derive
```
......
# Discussion du code `part08`
# Discussion du code `closures`
## Concepts
Les concepts abordés dans cet exemple sont:
- [Discussion du code `part08`](#discussion-du-code-part08)
- [Discussion du code `closures`](#discussion-du-code-closures)
- [Concepts](#concepts)
- [Documentation](#documentation)
- [Discussion](#discussion)
......@@ -12,7 +12,7 @@ Les concepts abordés dans cet exemple sont:
- [Fonction d'ordre supérieur](#fonction-dordre-supérieur)
- [Closures](#closures)
- [Exemples d'utilisation avec les options](#exemples-dutilisation-avec-les-options)
- [Rustlings](#rustlings)
- [Rustlings](#rustlings)
## Documentation
......@@ -57,7 +57,7 @@ fn add_one(x:i32) -> i32 {
Il est possible de stocker nos fonctions anonymes dans une variable, par exemple :
```rust,ignore
{{#include ../../codes/rust_lang/part08/src/main.rs:max_variable}}
{{#include ../../codes/rust_lang/closures/src/main.rs:max_variable}}
```
### Fonction d'ordre supérieur
......@@ -101,7 +101,7 @@ Dans un premier temps, nous pouvons généraliser le comportement de notre fonct
On commence par créer un type `BinaryOperator<T>` :
```rust,ignore
{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:binary_operator}}
{{#include ../../codes/rust_lang/closures/src/binary_operator.rs:binary_operator}}
```
Si on lit sa définition, on s'apperçoit qu'il s'agit d'une fonction qui prends deux éléments de type `T` et en retourne
......@@ -111,10 +111,10 @@ je détermine lequel est le plus petit et je le retourne.
Prenons maintenant le code de notre fonction du calcul du minimum généralisée :
```rust,ignore
{{#include ../../codes/rust_lang/part08/src/find.rs:find_with_hof}}
{{#include ../../codes/rust_lang/closures/src/find.rs:find_with_hof}}
```
Cette fonction est sensiblement la même que la fonction étudiée dans par la [partie 07](./part07.md). Le premier
Cette fonction est sensiblement la même que la fonction étudiée dans par la [partie 07](./gestion_erreurs.md). Le premier
changement qu'il faut remarquer, intervient au niveau des arguments.
On voit apparaître un nouvel argument `op: BinaryOperator<T>`. Il s'agit simplement de l'opération que
......@@ -132,16 +132,16 @@ En utilisant un autre type de fonction d'ordre supérieur, celles qui retournent
générer plusieurs opérateurs de ce type.
```rust,ignore
{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:minimum_operator}}
{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:maximum_operator}}
{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:sum_operator}}
{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:mul_operator}}
{{#include ../../codes/rust_lang/closures/src/binary_operator.rs:minimum_operator}}
{{#include ../../codes/rust_lang/closures/src/binary_operator.rs:maximum_operator}}
{{#include ../../codes/rust_lang/closures/src/binary_operator.rs:sum_operator}}
{{#include ../../codes/rust_lang/closures/src/binary_operator.rs:mul_operator}}
```
Pour l'utiliser ces fonctions rien de plus simple :
```rust,ignore
{{#include ../../codes/rust_lang/part08/src/main.rs:min_usage}}
{{#include ../../codes/rust_lang/closures/src/main.rs:min_usage}}
```
Il suffit d'appeler la fonction `minimum_operator` qui va nous retourner notre fonction anonyme capable de
......@@ -208,7 +208,7 @@ La fonction map permet de transformer le contenu d'une option si celle-ci n'est
dans le cas contraire. Prenons l'exemple suivant :
```rust,ignore
{{#include ../../codes/rust_lang/part08/src/main.rs:option_map}}
{{#include ../../codes/rust_lang/closures/src/main.rs:option_map}}
```
Dans le code ci-dessus, nous pouvons voir un exemple d'utilisation de la méthode map. Nous récupérons tout d'abord
la somme des éléments du tableau, sous forme d'option. Ensuite, pour transformer cette option, on utilise une closure,
......@@ -216,7 +216,7 @@ qui permet de diviser un `i32` par deux et qui retourne un `f32`. On transforme
Si la méthode `find_with_hof` retourne une option vide, alors l'option retournée par map reste `None`.
```rust,ignore
{{#include ../../codes/rust_lang/part08/src/main.rs:option_filter}}
{{#include ../../codes/rust_lang/closures/src/main.rs:option_filter}}
```
Ici, nous pouvons voir un exemple d'utilisation de la méthode filter. Nous cherchons le plus grand élément du tableau.
......
......@@ -8,9 +8,12 @@ Les concepts abordés dans cet exemple sont:
- [Concepts](#concepts)
- [Documentation](#documentation)
- [Discussion](#discussion)
- [Le type `Vec`](#le-type-vect)
- [Le type `Vec<T>`](#le-type-vect)
- [Le type `String`](#le-type-string)
- [Les slices](#les-slices)
- [Rustlings](#rustlings)
- [Les `Vec`](#les-vec)
- [Les `String`](#les-string)
## Documentation
......@@ -27,7 +30,7 @@ de se simplifier la vie lors de l'implémentation de divers algorithmes.
Dans ce chapitre, nous allons discuter des types `Vec<T>`, `String`, des slices.
Dans ce code nous modifions que très peu le code [de la partie 6](part06.md) afin
Dans ce code nous modifions que très peu le code [de la partie 6](tooling.md) afin
d'utiliser les types `Vec<i32>`, `String` et les slices.
### Le type `Vec<T>`
......
# Discussion du code `part03`
# Discussion du code `gen_types_composes`
Dans cette partie nous discutons de [ce code](#le-code).
......@@ -26,7 +26,7 @@ plus uniquement trouver le plus petit nombre dans une liste, mais on pourrait vo
trouver le mot le plus "petit" dans l'ordre lexicographique). Ainsi on a
```rust,no_run
{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:something_or_nothing}}
```
Il faut noter ici la présence du caractère générique `T`, qui est déclaré comme générique
......@@ -37,15 +37,15 @@ Maintenant qu'on a changé la définition de noter type, plus rien fonctionne et
le reste du code. Pour aller dans l'ordre, on doit modifier l'implémentation de la fonction `SomethingOrNothing::new(val)`
```rust,no_run
{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/part03/src/main.rs:new}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:new}}
```
On voit ici qu'il faut annoter tout le bloc `impl<T> SomethingOrNothing<T>` avec le type générique
afin qu'il puisse être réutilisé dans les fonctions statiques. En effet,
si on omet les `<T>` on une erreur de compilation
```rust,compile_fail
{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:something_or_nothing}}
impl SomethingOrNothing<T> {
fn new(val: T) -> SomethingOrNothing<T> {
SomethingOrNothing::Something(val)
......@@ -56,8 +56,8 @@ impl SomethingOrNothing<T> {
Afin d'illustrer une particularité de la généricité de Rust, nous avons également réécrit la fonction
`print(val)`
```rust,no_run
{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/part03/src/main.rs:print}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:print}}
```
On voit ici qu'il y a une annotation particulière dans l'entête de la fonction, `T: std::fmt::Display`
```rust,ignore
......@@ -75,7 +75,7 @@ Hors si on ne dit pas à notre programme comment faire cet affichage, il sera bi
nous devons donc préciser qu'il est **nécessaire** que `T` implémente le trait `Display`
sinon le programme ne compilera pas (cliquez sur play pour le vérifier)
```rust,compile_fail
{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:something_or_nothing}}
fn print<T>(val: SomethingOrNothing<T>) {
match val {
SomethingOrNothing::Nothing => println!("Nothing."),
......@@ -107,13 +107,13 @@ La fonctionnalité principale dont nous avons besoin pour que notre code fonctio
le minimum d'une liste de `SomethingOrNothing<T>` (voir l'appel à la fonction `current_minimum.min(SomethingOrNothing::new(t))`).
```rust,ignore
{{#include ../../codes/rust_lang/part03/src/main.rs:find_min}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:find_min}}
```
Ainsi on doit annoter `T` pour qu'il puisse calculer la plus petite valeur entre deux `SomethingOrNothing<T>`. On va donc devoir écrire définir notre premier *trait*.
On définit un trait à l'aide de la syntaxe suivante
```rust,no_run
{{#include ../../codes/rust_lang/part03/src/main.rs:minimum}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:minimum}}
```
Ici le trait `Minimum` sera implémenté sur un type qui implémente le trait `Copy` (un trait qui
garantit qu'on sait comment copier une valeur). Notre trait n'a que la fonction `min` (le nombre
......@@ -127,8 +127,8 @@ Il est important de vous rappeler qu'ici on ne sait pas encore quel est le type
L'implémentation de `Minimum` pour `SomethingOrNothing<T>` se fait comme suit
```rust,ignore
{{#include ../../codes/rust_lang/part03/src/main.rs:minimum}}
{{#include ../../codes/rust_lang/part03/src/main.rs:minimum_impl}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:minimum}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:minimum_impl}}
```
Pour implémenter un trait sur un type on utilise la syntaxe
......@@ -155,8 +155,8 @@ Comme nous utilisons des `SomethingOrNothing<i32>` dans ce code, nous devons imp
le trait `Minimum` pour des entiers. Ce qui est fait dans le bout de code suivant
```rust,no_run
{{#include ../../codes/rust_lang/part03/src/main.rs:minimum}}
{{#include ../../codes/rust_lang/part03/src/main.rs:minimum_i32}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:minimum}}
{{#include ../../codes/rust_lang/gen_types_composes/src/main.rs:minimum_i32}}
```
### Les tuples
......@@ -214,7 +214,7 @@ la valeur de `y` (ici `5`) est copiée dans une zone mémoire nouvellement allou
Dans notre code nous décidons d'autoriser la copie de notre type énuméré en implémentant le trait `Copy`
```rust,no_run
{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:copy}}
{{#rustdoc_include ../../codes/rust_lang/gen_types_composes/src/main.rs:copy}}
```
Comme on peut le voir ici, il n'y a pas de fonction à implémenter avec `Copy`, ce trait permet uniquement d'effectuer une copie binaire des données.
......@@ -224,20 +224,20 @@ Il est également important de noter qu'afin que notre type `SomethingOrNothing<
On peut aussi remarquer qu'il est possible d'indiquer la nécessité que les types implémentant un trait soit copiables. Par exemple
```rust,no_run
{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:minimum}}
{{#rustdoc_include ../../codes/rust_lang/gen_types_composes/src/main.rs:minimum}}
```
où la notation `trait Minimum: Copy` spécifie que `Copy` doit être implémenté quand on implémente `Minimum`.
Ici tous les types qui implémentent le trait `Minimum` doivent également implémenter `Copy`. C'est le cas par exemple du type `i32`
```rust,no_run
{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:minimum_i32}}
{{#rustdoc_include ../../codes/rust_lang/gen_types_composes/src/main.rs:minimum_i32}}
```
Le deuxième trait que nous retrouvons dans ce code est le trait `Clone`. `Clone` est un supertrait de `Copy`, ce qui signifie qu'un type qui implémente `Copy` doit nécessairement implémenter `Clone`.
Le trait `Clone` permet de dupliquer explicitement une instance. En effet, pour cloner une instance, il faut appeler la méthode `clone()` explicitement
```rust,no_run
{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:clone}}
{{#rustdoc_include ../../codes/rust_lang/gen_types_composes/src/main.rs:clone}}
```
Comme on peut le voir dans le code ci-dessus, il est possible de définir un comportement arbitraire en redéfinissant la méthode `clone()`.
......@@ -271,7 +271,7 @@ impl Clone for MyStruct {
## Le code
```rust
{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:main}}
{{#rustdoc_include ../../codes/rust_lang/gen_types_composes/src/main.rs:main}}
```
......
# Discussion du code `part07`
# Discussion du code `gestion_erreurs`
## Concepts
Les concepts abordés dans cet exemple sont:
- [Discussion du code `part07`](#discussion-du-code-part07)
- [Discussion du code `gestion_erreurs`](#discussion-du-code-gestion_erreurs)
- [Concepts](#concepts)
- [Documentation](#documentation)
- [Discussion](#discussion)
......@@ -15,6 +15,9 @@ Les concepts abordés dans cet exemple sont:
- [La macro panic!](#la-macro-panic)
- [Le type Result](#le-type-result)
- [L'opérateur ?](#lopérateur-)
- [Rustlings](#rustlings)
- [La gestion des erreurs](#la-gestion-des-erreurs)
- [Les options](#les-options)
## Documentation
......@@ -137,7 +140,7 @@ pub enum Option<T> {
}
```
C'est tout simplement d'un type énuméré qui contient soit une valeur sous la forme `Some(ma_valeur)` ou pas de valeur `None`. Il s'agit de la version générique du type `NumberOrNothing` vu dans la [partie 2](./part02.md).
C'est tout simplement d'un type énuméré qui contient soit une valeur sous la forme `Some(ma_valeur)` ou pas de valeur `None`. Il s'agit de la version générique du type `NumberOrNothing` vu dans la [partie 2](./bases2.md).
Nous pouvons donc réecrire notre structure `User` de cette manière :
......@@ -152,7 +155,7 @@ struct User {
Si nous reprenons notre exemple du minimum d'un tableau, nous pouvons écrire notre fonction de la manière suivante :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/find_minimum.rs:min_with_option}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/find_minimum.rs:min_with_option}}
```
Ici on commence par instancier notre minimum à `None`, puis on compare itérativement notre minimum avec
......@@ -162,7 +165,7 @@ Pour comparer deux options entre elles, nous avons implémenté le trait minimum
implémente le trait minimum. Ce qui nous donne :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/minimum.rs:min_for_option}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/minimum.rs:min_for_option}}
```
On peut voir ici que l'on décompose notre option grâce au pattern matching de Rust.
......@@ -212,7 +215,7 @@ que nous avons passé en argument à notre macro `panic!`.
Si nous reprenons notre exemple du minimum d'un tableau, nous pouvons écrire notre fonction de la manière suivante :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/find_minimum.rs:min_with_panic}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/find_minimum.rs:min_with_panic}}
```
La première chose que nous pouvons noter avec notre fonction est le type de retour. En effet, nous ne retournons pas
......@@ -282,7 +285,7 @@ Reprenons maintenant notre exemple du minimum d'un tableau. La première chose q
type représentant les erreurs que nous pourrions rencontrer en cherchant le minimum :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/find_minimum.rs:find_min_error}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/find_minimum.rs:find_min_error}}
```
Ici nous envisageons deux scénarios pouvant provoquer une erreur :
......@@ -294,7 +297,7 @@ décrivant l'erreur.
Une fois nos erreurs définies, nous pouvons passer à l'implémentation de notre fonction de recherche du minimum :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/find_minimum.rs:min_with_result}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/find_minimum.rs:min_with_result}}
```
Cette fonction n'est pas très différente des précédentes. On remarque à la fin que pour former un `Result`,
......@@ -304,7 +307,7 @@ Ici la seule erreur que nous retournons est la liste vide.
Pour traiter ce résultat, nous pouvons faire du pattern matching :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/main.rs:parse_result}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/main.rs:parse_result}}
```
Ici nous avons trois cas :
......@@ -363,7 +366,7 @@ l'opérateur `?` sur un type quelconque, je vous recommande [la documentation](h
Prenons un exemple directement tiré de notre code :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/find_minimum.rs:min_two_tabs_hand}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/find_minimum.rs:min_two_tabs_hand}}
```
Cette fonction prends deux tableaux en argument et va chercher quelle est la valeur minimum globale.
......@@ -382,7 +385,7 @@ le code est répetitif et rends le code la fonction moins lisible.
Avec l'opérateur `?` on peut simplement remplacer le test ainsi :
```rust,ignore
{{#include ../../codes/rust_lang/part07/src/find_minimum.rs:min_two_tabs_qm}}
{{#include ../../codes/rust_lang/gestion_erreurs/src/find_minimum.rs:min_two_tabs_qm}}
```
Ces deux fonctions font strictement la même chose. L'opérateur agit comme un sucre syntaxique qui permet
......
# Discussion du code `part10`
# Discussion du code `iterateurs`
## Concepts
Les concepts abordés dans cet exemple sont:
- [Discussion du code `part10`](#discussion-du-code-part10)
- [Discussion du code `iterateurs`](#discussion-du-code-iterateurs)
- [Concepts](#concepts)
- [Documentation](#documentation)
- [Discussion](#discussion)
......@@ -108,7 +108,7 @@ Ici, nous nous concentrerons sur les méthodes suivantes qui sont très communes
Reprenons notre code de recherche du minimum d'une liste :
```rust,ignore
{{#include ../../codes/rust_lang/part10/src/find.rs:find_minimum}}
{{#include ../../codes/rust_lang/iterateurs/src/find.rs:find_minimum}}
```
Notre fonction prend en argument un vecteur `v` que nous transformons en itérateur avec la méthode `iter()`. Pour trouver le minimum
......@@ -140,7 +140,7 @@ d'initialisation. Dans notre cas, il s'agit d'une `Option` vide.
Pour illustrer l'usage de la méthode `filter()`, nous avons une fonction qui trouve le plus petit nombre pair dans un vecteur :
```rust,ignore
{{#include ../../codes/rust_lang/part10/src/find.rs:find_even_minimum}}
{{#include ../../codes/rust_lang/iterateurs/src/find.rs:find_even_minimum}}
```
La méthode est similaire à la recherche du minimum, mais afin de garder uniquement les nombres pairs on ajoute la fonction `filter()`. Quand on ajoute ainsi
......@@ -157,14 +157,14 @@ Essayons maintenant de résoudre un problème un peu plus complexe en ajoutant l
Nous aimerions trouver quel est l'élément le plus petit en valeur absolue d'un vecteur donné.
```rust,ignore
{{#include ../../codes/rust_lang/part10/src/find.rs:find_absolute_minimum}}
{{#include ../../codes/rust_lang/iterateurs/src/find.rs:find_absolute_minimum}}
```
La première étape consiste à créer deux itérateurs. Le premier contient le signe de chaque élément
et le deuxième, la valeur absolue de chaque élément.
```rust,ignore
{{#include ../../codes/rust_lang/part10/src/find.rs:find_absolute_minimum_1}}
{{#include ../../codes/rust_lang/iterateurs/src/find.rs:find_absolute_minimum_1}}
```
Pour obtenir ces itérateurs, nous allons transformer nos itérateurs obtenus avec `iter()` en utilsant
......@@ -174,7 +174,7 @@ le nombre est positif, 0 si le nombre est 0 et -1 si le nombre est négatif. Pou
nous utilisons la méthode `abs()` des `i32`, qui retourne la valeur absolue d'un nombre.
```rust,ignore
{{#include ../../codes/rust_lang/part10/src/find.rs:find_absolute_minimum_2}}
{{#include ../../codes/rust_lang/iterateurs/src/find.rs:find_absolute_minimum_2}}
```
Maintenant que nous avons nos deux itérateurs, nous aimerions pouvoir itérer sur les deux simultanément.
......@@ -183,14 +183,14 @@ unique itérateur de tuple. Ici nous avons deux itérateurs de `i32`, qui devien
de type tuple `(i32, i32)`.
```rust,ignore
{{#include ../../codes/rust_lang/part10/src/find.rs:find_absolute_minimum_3}}
{{#include ../../codes/rust_lang/iterateurs/src/find.rs:find_absolute_minimum_3}}
```
Ensuite avec `fold()`, il nous suffit de comparer les valeurs absolues et de retourner une option contenant
le signe et la valeur absolue.
```rust,ignore
{{#include ../../codes/rust_lang/part10/src/find.rs:find_absolute_minimum_4}}
{{#include ../../codes/rust_lang/iterateurs/src/find.rs:find_absolute_minimum_4}}
```
Pour finir, on utilise la méthode `map()` de notre `Option<(i32,i32)>` pour multiplier
......
# Discussion du code `part05`
# Discussion du code `modules_visibilite`
Dans cette partie nous discutons de [ce code](#le-code).
......@@ -20,7 +20,7 @@ cela se passe pour le Rust. Pour plus d'informations vous pouvez vous référer
Afin de séparer le code en plusieurs fichiers il est nécessaire de créer un fichier `lib.rs` qui se trouve dans le même répertoire que le fichier `main.rs`. Ce répertoire est en général le répertoire `src` de votre projet. Ici c'est dans `projet05/src`. Dans notre cas, il contient très peu de lignes
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/lib.rs:lib_modules}}
{{#include ../../codes/rust_lang/modules_visibilite/src/lib.rs:lib_modules}}
```
La présence d'un fichier `lib.rs` indique que vous avez créé une *librairie*, appelée `crate` en Rust.
......@@ -30,7 +30,7 @@ Toutes les libraries publiées en Rust sont des `crate` et peuvent se téléchar
On voit qu'il y a dans le fichier `lib.rs` la définition de la constante `SIZE`, ainsi que trois lignes
contenant le mot-clé `mod` qui indique la présence d'un **module**. Par défaut, le compilateur Rust va aller chercher
le contenu de ces modules dans les fichiers `io.rs`, `minimum.rs`, et `something_or_nothing.rs`
(ou `io/mod.rs`, `minimum/mod.rs`, et `something_or_nothing/mod.rs`). Dans ce chapitre, nous avons simplement réparti tout le code qui se trouvait dans `main.rs` dans la [partie 4](part04.md). Le mot-clé
(ou `io/mod.rs`, `minimum/mod.rs`, et `something_or_nothing/mod.rs`). Dans ce chapitre, nous avons simplement réparti tout le code qui se trouvait dans `main.rs` dans la [partie 4](propriete.md). Le mot-clé
`pub` indique la **visibilité** du module à l'intérieur de votre librairie.
Ainsi, le module `minimum` n'est pas exposé à vos utilisatrices et utilisateurs, alors que `io` et `something_or_nothing` le sont. Nous verrons un peu plus bas les règles sur la visibilité.
......@@ -38,14 +38,14 @@ Afin d'utiliser les fonctions définies dans notre librairie dans notre programm
comme dans le code suivant
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/main.rs:main_imports}}
{{#include ../../codes/rust_lang/modules_visibilite/src/main.rs:main_imports}}
```
Pour importer les modules avec la syntaxe suivante
```rust,ignore
use nom_de_la_crate::nom_du_module;
```
où le `nom_de_la_crate` est défini dans le fichier `part05/Cargo.toml` (le champs `name`),
où le `nom_de_la_crate` est défini dans le fichier `modules_visibilite/Cargo.toml` (le champs `name`),
le nom du module ici est `io` et chaque module est séparé par le symbole `::`.
On a également importé la fonction `find_min` spécifiquement
avec la syntaxe
......@@ -59,7 +59,7 @@ Ce n'est pas fait dans cet exemple, mais il est tout à fait possible de défini
Afin d'utiliser de partager des fonctions entre les modules, il faut également les importer comme dans le module `something_or_nothing` qui nécessite l'import du trait `Minimum` à l'aide de la syntaxe
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/something_or_nothing.rs:minimum}}
{{#include ../../codes/rust_lang/modules_visibilite/src/something_or_nothing.rs:minimum}}
```
On voit la nécessité d'utiliser le mot-clé `crate` pour indiquer que le module est importé depuis
......@@ -81,12 +81,12 @@ error[E0432]: unresolved import `crate::minimum`
| ^^^^^^^ could not find `minimum` in the crate root
For more information about this error, try `rustc --explain E0432`.
error: could not compile `part05` (lib) due to previous error
error: could not compile `modules_visibilite` (lib) due to previous error
```
Pour la partie `2`, on a deux messages un peu différents
```bash
Compiling part05 v0.1.0 (/home/orestis/git/projects/rust-101/codes/rust_lang/part05)
Compiling modules_visibilite v0.1.0 (/home/orestis/git/projects/rust-101/codes/rust_lang/modules_visibilite)
warning: function `read_command_line` is never used
--> src/io.rs:2:8
|
......@@ -101,21 +101,21 @@ warning: function `print_tab` is never used
8 | pub fn print_tab(tab: &[i32; crate::SIZE]) {
| ^^^^^^^^^
warning: `part05` (lib) generated 2 warnings
warning: `modules_visibilite` (lib) generated 2 warnings
error[E0603]: module `io` is private
--> src/main.rs:2:13
|
2 | use part05::io;
2 | use modules_visibilite::io;
| ^^ private module
|
note: the module `io` is defined here
--> /home/orestis/git/projects/rust-101/codes/rust_lang/part05/src/lib.rs:9:1
--> /home/orestis/git/projects/rust-101/codes/rust_lang/modules_visibilite/src/lib.rs:9:1
|
9 | mod io;
| ^^^^^^
For more information about this error, try `rustc --explain E0603`.
error: could not compile `part05` (bin "part05") due to previous error
error: could not compile `modules_visibilite` (bin "modules_visibilite") due to previous error
```
Le compilateur commence par nous prévenir par des *warnings* que les fonctions `print_tab` et `read_command_line()` ne sont jamais utilisées. Puis, nous avons un message nous prévenant que `io` est privé.
......@@ -128,7 +128,7 @@ Il y a plusieurs exemples de l'utilisation dans ce chapitre.
- Pour les fonctions:
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/io.rs:pub_fn}}
{{#include ../../codes/rust_lang/modules_visibilite/src/io.rs:pub_fn}}
```
on voit qu'on préfixe `pub` devant le mot-clé `fn` pour rendre la fonction publique. Si on le retire, le compilateur donnera le message d'erreur suivant
```bash
......@@ -139,7 +139,7 @@ error[E0603]: function `print_tab` is private
| ^^^^^^^^^ private function
|
note: the function `print_tab` is defined here
--> /home/orestis/git/projects/rust-101/codes/rust_lang/part05/src/io.rs:9:1
--> /home/orestis/git/projects/rust-101/codes/rust_lang/modules_visibilite/src/io.rs:9:1
|
9 | fn print_tab(tab: &[i32; crate::SIZE]) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -148,17 +148,17 @@ For more information about this error, try `rustc --explain E0603`.
```
- Pour un type énuméré:
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/something_or_nothing.rs:pub_enum}}
{{#include ../../codes/rust_lang/modules_visibilite/src/something_or_nothing.rs:pub_enum}}
```
où on préfixe le mot clé `enum` avec un `pub`.
- Pour les méthodes
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/something_or_nothing.rs:pub_method}}
{{#include ../../codes/rust_lang/modules_visibilite/src/something_or_nothing.rs:pub_method}}
```
où comme pour les fonctions, on préfixe `fn` avec un `pub`.
- Pour les traits:
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/minimum.rs:trait}}
{{#include ../../codes/rust_lang/modules_visibilite/src/minimum.rs:trait}}
```
il faut noter que seule la définition du trait a besoin d'être publique. L'implémentation pour un type particulier n'a pas besoin de l'être.
......
# Part 09
# Part 11
# Discussion du code `part04`
# Discussion du code `propriete`
Dans cette partie nous discutons de [ce code](#le-code).
......@@ -13,7 +13,7 @@ Les concepts abordés dans cet exemple sont:
### Bind et move
On l'a déjà brièvement mentionné dans la [partie 2](part02.md) l'instruction
On l'a déjà brièvement mentionné dans la [partie 2](types_avances.md) l'instruction
```rust,no_run
let a = 2;
......@@ -30,7 +30,7 @@ où est contenue la valeur `2` est libéré automatiquement). Cela se passe auss
Si on écrit le code un peu plus compliqué
```rust,compile_fail
{{#include ../../codes/rust_lang/part04/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:something_or_nothing}}
fn main() {
let a = SomethingOrNothing::new(1);
let _b = a;
......@@ -66,7 +66,7 @@ n'est pas copiable, la propriété de la valeur est passée à l'argument de la
Ainsi au moment de quitter la fonction la valeur est détruite et la mémoire liée à la valeur libérée
comme dans le code suivant
```rust,compile_fail
{{#include ../../codes/rust_lang/part04/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:something_or_nothing}}
fn print<T: std::fmt::Display>(val: SomethingOrNothing<T>) {
match val {
SomethingOrNothing::Nothing => println!("Nothing."),
......@@ -95,8 +95,8 @@ Le Rust nous offre un moyen d'*emprunter* (borrow) les variables pour éviter d'
ou de devoir toujours retourner les variables passées en argument.
```rust
{{#include ../../codes/rust_lang/part04/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/part04/src/main.rs:print}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:print}}
fn main() {
let a = SomethingOrNothing::new(1);
print(&a);
......@@ -119,7 +119,7 @@ Il faut bien noter que la *référence* a la syntaxe `&<variable>` comme en C.
Corrigez ce code pour qu'il compile (sans enlever de lignes évidemment)
```rust,editable,compile_fail
{{#include ../../codes/rust_lang/part04/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:something_or_nothing}}
fn main() {
let a = SomethingOrNothing::new(1);
{
......@@ -138,7 +138,7 @@ La fonction `print()` a déjà été discutée plus haut, et nécessite simpleme
l'ajout d'une référence vers un `SomethingOrNothing<T>` pour que la valeur soit
prêtée à `val` dans la fonction
```rust,ignore
{{#include ../../codes/rust_lang/part04/src/main.rs:print}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:print}}
```
Ainsi, les valeurs de `SomethingOrNothing<T>` ne sont pas détruites à l'appel de `print()`.
......@@ -146,7 +146,7 @@ La fonction `print_tab()`, de façon similaire, nécessite le passage de la réf
vers le tableau statique `&[T; SIZE]`
```rust,ignore
{{#include ../../codes/rust_lang/part04/src/main.rs:print_tab}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:print_tab}}
```
La boucle for nécessite une discussion plus approfondie. En effet,
......@@ -169,7 +169,7 @@ print!("{} ", t);
Finalement, nous avons également modifié la fonction `find_min()`.
```rust,ignore
{{#include ../../codes/rust_lang/part04/src/main.rs:find_min}}
{{#include ../../codes/rust_lang/propriete/src/main.rs:find_min}}
```
Outre l'argument qui est une référence à un tableau statique comme dans les deux autres fonctions
discutées précédemment, on a une nouvelle syntaxe dans la boucle `for`
......@@ -186,7 +186,7 @@ le vérificateur de type du Rust ne laisse pas passer ce genre de choses.
## Le code
```rust
{{#rustdoc_include ../../codes/rust_lang/part04/src/main.rs:main}}
{{#rustdoc_include ../../codes/rust_lang/propriete/src/main.rs:main}}
```
## Rustlings
......
# Discussion du code `part06`
# Discussion du code `tooling`
## Concepts
......@@ -47,31 +47,31 @@ directement au dessus du composant à commenter. Ainsi les exemples suivants per
* Documenter une constante
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/lib.rs:size}}
{{#include ../../codes/rust_lang/tooling/src/lib.rs:size}}
```
* Documenter une fonction
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/io.rs:function}}
{{#include ../../codes/rust_lang/tooling/src/io.rs:function}}
```
* Documenter une fonction statique
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/something_or_nothing.rs:static_function}}
{{#include ../../codes/rust_lang/tooling/src/something_or_nothing.rs:static_function}}
```
* Documenter un trait
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/minimum.rs:minimum}}
{{#include ../../codes/rust_lang/tooling/src/minimum.rs:minimum}}
```
* Documenter un type énuméré et ses variantes
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/something_or_nothing.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/tooling/src/something_or_nothing.rs:something_or_nothing}}
```
#### La documentation d'une `crate` et des modules
......@@ -81,7 +81,7 @@ sur le fonctionnement d'une librairie, on peut utiliser une syntaxe spéciale `/
ligne de documentation (on peut également utiliser la syntaxe `/*! ... */`), comme ci-dessous
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/lib.rs:crate}}
{{#include ../../codes/rust_lang/tooling/src/lib.rs:crate}}
```
Cette documentation se met dans le fichier `lib.rs` qui est également l'endroit où on importe les différents modules.
......@@ -89,7 +89,7 @@ Cette documentation se met dans le fichier `lib.rs` qui est également l'endroit
On peut également documenter les modules individuellement. Pour ce faire, il faut utiliser la même syntaxe que pour la documentation de la crate, mais mettre cette documentation au début du fichier contenant chaque module comme par exemple au début du fichier `io.rs`
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/io.rs:io_module}}
{{#include ../../codes/rust_lang/tooling/src/io.rs:io_module}}
```
......@@ -120,7 +120,7 @@ Rust propose un framework de tests totalement intégré au langage. On peut ains
des fonctions de test en ajoutant l'annotation `#[test]` directement au dessus de n'importe quelle fonction
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/lib.rs:test_creation}}
{{#include ../../codes/rust_lang/tooling/src/lib.rs:test_creation}}
```
La fonction `test_creation()` sera automatiquement appelée lors de l'appel à la commande
......@@ -155,8 +155,8 @@ note: an implementation of `PartialEq<_>` might be missing for `SomethingOrNothi
Ainsi, on doit implémenter le trait `PartialEq` pour le type `SomethingOrNothing<T>`,
qui permet de tester l'égalité entre deux instances d'un type
```rust
{{#include ../../codes/rust_lang/part06/src/something_or_nothing.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/part06/src/something_or_nothing.rs:partial_eq}}
{{#include ../../codes/rust_lang/tooling/src/something_or_nothing.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/tooling/src/something_or_nothing.rs:partial_eq}}
fn main() {
let n1 = SomethingOrNothing::<i32>::Nothing;
assert!(n1 == SomethingOrNothing::<i32>::Nothing);
......@@ -168,7 +168,7 @@ alors nous avons égalité.
On peut également vouloir construire des tests qui échouent comme dans l'exemple ci-dessous
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/lib.rs:should_panic}}
{{#include ../../codes/rust_lang/tooling/src/lib.rs:should_panic}}
```
où on a annoté le test avec un `#[should_panic]`. Ce test, bien qu'il panique, sera considéré
comme réussi. Il faut néanmoins rester prudent avec ce type de test. Rien ne garantit que la fonction de test a paniqué au moment espéré. Le code pourrait tout à fait paniquer pour une raison autre que celle attendue. Cela est particulièrement vrai si le test est complexe.
......@@ -176,14 +176,14 @@ comme réussi. Il faut néanmoins rester prudent avec ce type de test. Rien ne g
Finalement, il y a également la possibilité de regrouper les tests
comme ci-dessous (dans le fichier `lib.rs` dans cet exemple)
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/lib.rs:cfg_test}}
{{#include ../../codes/rust_lang/tooling/src/lib.rs:cfg_test}}
```
Pour ce faire, il faut créer un module, (ici `mod tests`) et l'annoter avec une configuration spéciale `#[cfg(test)]`. Cela permet de séparer les tests totalement du reste du code et devoir
importer les différentes implémentations.
Il est également possible de répartir les tests dans différents modules comme dans `minimum.rs` par exemple en plus de `lib.rs`
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/minimum.rs:cfg_test_min}}
{{#include ../../codes/rust_lang/tooling/src/minimum.rs:cfg_test_min}}
```
### Tests de documentation
......@@ -195,21 +195,21 @@ markdown sera compilé et exécuté (à moins qu'il soit annoté `ignore` où il
[Default](https://doc.rust-lang.org/std/default/trait.Default.html) pour `SomethingOrNothing` qui permet
de construire une instance par défaut qui sera la variante `Nothing` (voir `something_or_nothing.rs`).
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/something_or_nothing.rs:default}}
{{#include ../../codes/rust_lang/tooling/src/something_or_nothing.rs:default}}
```
On voit que pour que le test puisse compiler et s'exécuter il est nécessaire d'importer les bons modules/fonctions. Ici on importe
explicitement `part06::something_or_nothing::SomethingOrNothing` et on met les fonctions à exécuter dans un main.
explicitement `tooling::something_or_nothing::SomethingOrNothing` et on met les fonctions à exécuter dans un main.
Pour que ce "bruit" n'apparaisse pas dans la documentation, on préfixe les lignes par des `#`. Ainsi ces lignes
sont lues par le compilateur pour les tests de documentation mais sont ignorées lors du rendu de la documentation.
Il y a également un exemple sur l'utilisation de la fonction `find_min()` (toujours dans `something_or_nothing.rs`)
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/something_or_nothing.rs:find_min}}
{{#include ../../codes/rust_lang/tooling/src/something_or_nothing.rs:find_min}}
```
Finalement, les tests de documentation peuvent également être mis dans les documentation de module comme dans `minimum.rs`
```rust,ignore
{{#include ../../codes/rust_lang/part06/src/minimum.rs:min}}
{{#include ../../codes/rust_lang/tooling/src/minimum.rs:min}}
```
#### Rapport sur l'exécution des tests
......@@ -218,9 +218,9 @@ Lors de l'appel à `cargo test` tous les tests sont exécutés et un rapport est
[ce code](#le-code), on obtient
```bash
$ cargo est
Compiling part06 v0.1.0 (/home/orestis/git/projects/rust-101/codes/rust_lang/part06)
Compiling tooling v0.1.0 (/home/orestis/git/projects/rust-101/codes/rust_lang/tooling)
Finished test [unoptimized + debuginfo] target(s) in 0.37s
Running unittests src/lib.rs (target/debug/deps/part06-f12750c4987ae624)
Running unittests src/lib.rs (target/debug/deps/tooling-f12750c4987ae624)
running 5 tests
test test_creation ... ok
......@@ -231,13 +231,13 @@ test tests::test_min_something_or_nothing ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/main.rs (target/debug/deps/part06-b63e62707c6aab7d)
Running unittests src/main.rs (target/debug/deps/tooling-b63e62707c6aab7d)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests part06
Doc-tests tooling
running 3 tests
test src/minimum.rs - minimum (line 8) ... ok
......
# Discussion du code `part02`
# Discussion du code `bases2`
## Concepts
......
......@@ -80,7 +80,7 @@ For more information about this error, try `rustc --explain E0072`.
error: could not compile `playground` (bin "playground") due to previous error
```
Ainsi, comme nous le recommande le compilateur, il faut utiliser un `Box` (voir le [chapitre 10](part10.md)) pour faire une allocation sur le tas de `next`.
Ainsi, comme nous le recommande le compilateur, il faut utiliser un `Box` (voir le [chapitre 10](iterateurs.md)) pour faire une allocation sur le tas de `next`.
```rust
struct Element {
......@@ -91,17 +91,17 @@ struct Element {
Nous ne sommes pas encore sortis d'affaire, car notre type élément ne permet pas de représenter la fin de la chaîne. Il faudrait que
`next` soit un élément suivant soit pas d'élément suivant (indiquant ainsi la fin de la chaîne). Mais on connaît un tel type non?
Le type `Option<T>` (voir le [chapitre 7](part07.md)) fait exactement ce que nous voulons: la variante `Some(element)` indique la présence
Le type `Option<T>` (voir le [chapitre 7](gestion_erreurs.md)) fait exactement ce que nous voulons: la variante `Some(element)` indique la présence
d'un élément suivant, alors que la variante `None` indique son absence.
```rust
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:element}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:element}}
```
Il ne nous reste plus qu'à créer la structure de liste chaînée, qui va juste avoir la forme suivante:
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:linked_list}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:linked_list}}
```
Et juste posséder la tête de la liste chaînée.
......@@ -112,7 +112,7 @@ en prendre la propriété. Cela aura des effets non négligeables sur l'ergonomi
La fonction `new()` est triviale à écrire
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:new}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:new}}
```
Il faut juste noter que `new()` retourne une nouvelle instance de `LinkedList` dont la tête est `None` (il n'y a aucun élément dans la liste).
......@@ -134,7 +134,7 @@ méthode `is_none()` de la librairie standard de Rust. Mais cela reviendrait à
emprunter `self` ce qui contreviendrait au principe qu'on s'est fixé pour cette implémentation
un peu étrange.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:is_empty}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:is_empty}}
```
#### La méthode `push()`
......@@ -143,7 +143,7 @@ La fonction `push(value)` doit créer un élément à placer en tête de liste q
Il y a différentes façons de l'implémenter. Ici, nous allons prendre possession de l'instance de la liste, et retourner
une nouvelle liste avec le nouvel élément ajouté
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:push}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:push}}
```
Dans cette implémentation on voit que `self` est "move" dans la fonction `push` (on prend en argument `self` et non `&self` ou `&mut self`). Puis ont crée un nouvel élément
contenant `data` et la tête actuelle de la liste. Le nouvel élément `elem` a donc
......@@ -153,7 +153,7 @@ la propriété de la mémoire de `self.head`.
La fonction `pop()`
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:pop}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:pop}}
```
retourne une `Option<i32>` avec éventuellement une valeur si la liste n'est pas vide, et retourne une nouvelle liste où la tête
est soit l'élément suivant soit une liste vide (si on est à la fin de la liste).
......@@ -165,14 +165,14 @@ du pattern matching et raccourcir sensiblement le code.
Finalement, la fonction `print()` est probablement la plus étrange de toutes.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:print}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:print}}
```
En effet, on aimerait ne pas avoir à détruire notre liste en entier lorsque nous la parcourons.
Ainsi, la fonction `print()` prend en argument `self` et retourne `Self`.
Cette fonction va créer une nouvelle instance de `LinkedList` mutable,
puis parcourir tous les éléments de la liste `self` à l'aide de la boucle
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:while}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:while}}
```
où on va parcourir la liste en "consommant" les éléments: lors de l'assignation
de `current` à `tmp.next`, l'ancienne valeur de `current` sort de la portée et est détruite automatiquement. Ainsi, il est nécessaire de `push()` la valeur `tmp.data`
......@@ -215,7 +215,7 @@ lists..." mais... cela ne fonctionne pas non plus pour des raisons trop complexe
expliquer ici. La seule solution est d'implémenter une fonction vidant la liste et de l'appeler à la main et perd un peu la raison d'être du Rust.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/immutable_linked_list/mod.rs:clear}}
{{#include ../../codes/rust_lang/unsafe/src/immutable_linked_list/mod.rs:clear}}
fn main() {
// Exemple de stack overflow
let mut immutable_list = ImmutableList::new();
......@@ -263,15 +263,15 @@ et les prêts restent valides. On peut pas faire n'importe quoi tout de même!
La structure de données de la liste chaînée reste identique à celle que nous avons vue plus haut, ainsi que la création d'une nouvelle liste.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:element}}
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:linked_list}}
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:new}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:element}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:linked_list}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:new}}
```
Ici, nous ne nous interdisons pas d'utiliser des références et d'emprunter les instances
de notre liste. Ainsi, la fonction `is_empty()` est simplement
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:is_empty}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:is_empty}}
```
où on a bien une référence vers `self` en argument de `is_empty`.
......@@ -298,7 +298,7 @@ La solution simple et élégante est d'utiliser la méthode `take()` implément
les `Option<T>` qui retourne la valeur de l'option et la remplace par `None`.
Ainsi, le compilateur est content: on a pas move `self.head`, mais on l'a juste muté.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:push}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:push}}
```
On a donc un `push()` fonctionnel. Mais on ne sait pas vraiment ce qui se passe
dans le `take()` et ça semble un peu trop "magique" pour être `safe`.
......@@ -331,8 +331,8 @@ gère pas la libération de la mémoire de `self.head`).
Combinées ces deux opérations `read()/write()` sont sûres, mais le compilateur n'a aucun moyen de le déduire et nous avons dû recourir à des opérations `unsafe` bien qu'emballées dans des fonctions parfaitement `safe`! Nous n'avons donc plus de garantie de la part du compilateur,
et par conséquent, la responsabilité de la gestion de la mémoire nous revient (cf. les [travaux du Pr. Ben](https://youtu.be/s0F3Tvc-3eI)).
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:push_replace}}
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:push_unsafe}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:push_replace}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:push_unsafe}}
```
Dans ce code, nous voyons dans le commentaire l'utilisation d'un mot peut-être inconnu: `aliasing`.
L'aliasing décrit une situation dans laquelle un emplacement de données en mémoire peut être accessible
......@@ -351,7 +351,7 @@ code dans une fonction `safe` afin de limiter les cas d'utilisation.
La fonction `pop()` prend en argument `&mut self` et modifie donc l'instance de la liste chaînée sur laquelle elle s'applique. Elle a aussi recours à la fonction `take()` comme `push()`.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:pop}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:pop}}
```
Si nous nous limitions à `self.head.take()`, nous retournerions la tête de la liste,
après l'avoir remplacée par `None`. Cela casserait évidemment la liste chaînée de
......@@ -364,7 +364,7 @@ l'option est `None`). Ici, nous retournons les données stockées dans l'éléme
La fonction `print()` est également bien plus élégante que celle vue précédemment.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/safe_linked_list/mod.rs:print}}
{{#include ../../codes/rust_lang/unsafe/src/safe_linked_list/mod.rs:print}}
```
En effet, elle ne prend qu'une référence vers la liste et va se contenter de parcourir tous
les éléments sans libérer la mémoire.
......@@ -410,7 +410,7 @@ Sans l'annotation unsafe on a l'erreur suivante
```console
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
--> /tmp/mdbook-1nmQ54/part12.md:450:5
--> /tmp/mdbook-1nmQ54/unsafe.md:450:5
|
5 | *p_to_value = 10;
| ^^^^^^^^^^^^^^^^ dereference of raw pointer
......@@ -426,7 +426,7 @@ For more information about this error, try `rustc --explain E0133`
La structure de données d'un élément ressemble beaucoup à ce qu'on écrirait en C
```rust
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:element}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:element}}
```
Un `Element` contient, `data`, les données qui sont stockées dans chaque élément (un `i32` ici)
et un raw pointer **mutable** sur l'élément suivant: `next`. Il est très important que ce pointeur
......@@ -437,7 +437,7 @@ comme en C, par un pointeur `null`.
Un nouvel `Element` est créé à l'aide de la fonction `new()`
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:new}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:new}}
```
qui prend en argument les données à stocker dans l'élément et le pointeur suivant.
On constate que pour allouer un élément, on doit préciser son "layout" en mémoire,
......@@ -455,7 +455,7 @@ implémente la fonction `drop()`. Pour des raw pointers, la fonction `drop()` **
il est nécessaire d'appeler `dealloc()` manuellement et donc il est nécessaire
de faire l'implémentation explicitement.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:drop}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:drop}}
```
On voit que pour libérer la mémoire, on doit vérifier que le pointeur
qu'on essaie de libérer n'est pas `null` afin d'éviter de tenter de désallouer
......@@ -471,12 +471,12 @@ les bugs mémoire plus facilement, car ils se trouvent toujours liés à ces par
Maintenant que nous pouvons créer des nouveaux éléments (et les détruire), nous pouvons passer à la liste chaînée qui n'est rien d'autre qu'un pointeur d'`Element` mutable nommé astucieusement `head`.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:linked_list}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:linked_list}}
```
Pour créer une nouvelle liste chaînée, nous avons uniquement besoin de signaler
que la liste est vide en assignant à `head` un *pointeur nul mutable* (`ptr::nul_mut()`).
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:ll_new}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:ll_new}}
```
#### La fonction `is_empty()`
......@@ -484,14 +484,14 @@ que la liste est vide en assignant à `head` un *pointeur nul mutable* (`ptr::nu
Naturellement, la fonction `is_empty()` va uniquement vérifier que la tête de la liste
est nulle et est trivialement implémentée
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:is_empty}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:is_empty}}
```
#### La fonction `push()`
La fonction `push()` est très simple à écrire et équivalente à ce qu'on ferait en C
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:push}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:push}}
```
La relaxation des règles très strictes sur les références permet de déplacer le pointeur de tête dans
le nouvel élément qui devient ainsi la nouvelle tête de la liste.
......@@ -501,7 +501,7 @@ le nouvel élément qui devient ainsi la nouvelle tête de la liste.
La fonction `pop()` est un peu plus complexe, mais également très similaire à ce qu'on
ferait en C.
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:pop}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:pop}}
```
Si la liste est vide, on retourne un `None` (aucune valeur) car il n'y a rien à retourner.
En revanche, si un élément est présent en tête de liste on garde un pointeur sur la copie de l'élément de tête, `old_head`, puis on déplace le pointeur de tête sur l'élément suivant
......@@ -513,7 +513,7 @@ on termine par retourner la valeur qui était stockée au sommet de la liste cha
La fonction `print()` est relativement simple et très similaire à ce qu'on fait en C
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:print}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:print}}
```
On crée un pointeur mutable qui va parcourir tous les éléments de la liste chaînée et en afficher le contenu, jusqu'à atteindre la fin de la liste (le pointeur devient `null`). Les raw pointers n'appelant jamais `drop()` quand ils sortent de la portée
ne libèrent jamais la mémoire sur laquelle ils pointent donc la liste chaînée reste intacte.
......@@ -523,7 +523,7 @@ ne libèrent jamais la mémoire sur laquelle ils pointent donc la liste chaîné
Comme on l'a dit tout à l'heure pour les `Element`, il est nécessaire d'implémenter
le trait `Drop`
```rust,ignore
{{#include ../../codes/rust_lang/part12/src/unsafe_linked_list/mod.rs:ll_drop}}
{{#include ../../codes/rust_lang/unsafe/src/unsafe_linked_list/mod.rs:ll_drop}}
```
Ici toutes les désallocations sont cachées dans la fonction `pop()`, et on parcourt
toute la liste comme on l'a fait pour [la fonction `print()`](#la-fonction-print-2).
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment