-[Discussion du code `part10`](#discussion-du-code-part10)
-[Concepts](#concepts)
-[Documentation](#documentation)
-[Discussion](#discussion)
-[Le trait itérateur](#le-trait-itérateur)
-[Les fonctions `iter` et `collect`](#les-fonctions-iter-et-collect)
-[Quelques fonctions d'ordre supérieur sur les itérateurs](#quelques-fonctions-dordre-supérieur-sur-les-itérateurs)
-[Performances et lazy evaluation](#performances-et-lazy-evaluation)
-[Rustlings](#rustlings)
-[Les itérateurs](#les-itérateurs)
## Documentation
Afin de compléter ce cours, je vous recommande la lecture des ressources suivantes :
-[Traitements des collections avec de itérateurs en Rust](https://doc.rust-lang.org/book/ch13-02-iterators.html)
-[Le trait Iterator en Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html)
-[Les méthodes du trait Iterator](https://doc.rust-lang.org/std/iter/trait.Iterator.html#provided-methods)
## Discussion
### Le trait itérateur
L'itérateur est un patron de conception extrêment répandu en prorgrammation orientée objet. On le retrouve
dans plusieurs langages comme par exemple python.
Le trait `Iterator` est défini ainsi en version simplifiée dans la documentation :
```rust
traitIterator{
typeItem;
fnnext(&mutself)->Option<Self::Item>;
}
```
Un itérateur possède donc un élément courant et une méthode `next()` qui permet de passer à l'élément suivant,
puis de retourner l'élément courant. Un itérateur peut-être fini ou infini. Il peut permettre par exemple de
parcourir une collection ou de créer un compteur.
La documentation Rust offre [un exemple d'implémentation d'itérateur assez accessible](https://doc.rust-lang.org/std/iter/index.html#implementing-iterator).
### Les fonctions `iter` et `collect`
Le Rust propose des méthodes permettant de passer d'une collection à un itérateur assez facilement.
```rust
# fn main(){
letv:Vec<i32>=vec![1,2,3,4];
letmutv_iter=v.iter();
println!("{}",v_iter.next().unwrap());
println!("{}",v_iter.next().unwrap());
println!("{}",v_iter.next().unwrap());
println!("{}",v_iter.next().unwrap());
assert!(v_iter.next().is_none());
# }
```
La méthode `iter()` des vecteurs permet de créer un itérateur à partir d'un vecteur. Il faut noter que `v_iter` est mutable, car son état interne est **modifié** par l'appel à la méthode `next()`.
En effet, pour pouvoir avancer dans notre itérateur, nous utilisons la fonction `next()` qui avance l'élément courant d'une position
et retourne une `Option` sur l'élément courant. Pour rappel, la signature de la méthode de `next()` est `fn next(&mut self) -> Option<Self::Item>;`.
Il est aussi possible de transformer un itérateur en collection à l'aide de la méthode `collect()`. La fonction `from_fn()` permet
de créer un itérateur à l'aide d'une fonction :
```rust
# fn main(){
letmutcount=0;
leteven_counter=std::iter::from_fn(||{
count+=2;
Some(count)
});
letv:Vec<i32>=even_counter.take(3).collect();
println!("Les 3 premiers nombres paires sont {}, {}, {}",v[0],v[1],v[2])
# }
```
Le code ci-dessus commence par créer un itérateur infini de nombres paires. Nous verrons plus-tard que les éléments de l'itérateur infini n'est pas généré immédiatement
[dans la section lazy-evaluation](#performances-et-lazy-evaluation).
Nous utilisons une variable mutable `count`, afin de générer les valeurs de notre itérateur.
Notre closure va capturer cette variable et l'incrémenter de 2 à chaque appel et retourner la valeur courante encapsulée dans une `Option`.
Notre itérateur étant infini, nous devons le limiter à un nombre fini d'éléments avant de pouvoir récupérer une collection.
Pour cela nous utilisons la méthode `take()` qui permet de limiter la taille de notre itérateur. Finalement, nous pouvons
récupérer un vecteur d'entier à l'aide de la méthode `collect()`.
### Quelques fonctions d'ordre supérieur sur les itérateurs
L'intérêt principal des itérateurs en Rust réside dans ses fonctions d'ordre supérieur. Elle permettent de traiter des collections
de manière efficaces en apportant des garanties notament en terme de concurrence. On retrouve notament le crate
[Rayon-rs](https://github.com/rayon-rs/rayon) qui permet d'effectuer des traitement en parallèle sans apporter de modifications
majeures au code.
Ici, nous nous concentrerons sur les méthodes suivantes qui sont très communes dans les langages fonctionnels (pas toujours avec les mêmes noms) :
-`map()`
-`filter()`
-`fold()`
-`zip()`
Reprenons notre code de recherche du minimum d'une liste :
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
une série de traitements à la suite, on parle de pipelines.
La fonction `filter()` prend une fonction en paramètre appelée prédicat. Un prédicat et une fonction qui prend un élément et retourne un booléen.
Cette fonction va déterminer quels éléments conserver. Ici nous utilisons une closure qui retourne `true` si le nombre est pair. La méthode `filter()`
va retourner un nouvel itérateur composé uniquement des éléments séléctionnés par le prédicat.
Pour finir, on recherche la valeur minimum de ce nouvel itérateur, de la même façon que dans l'exemple
précédent, à l'aide de la méthode `fold()`.
Essayons maintenant de résoudre un problème un peu plus complexe en ajoutant les méthodes `zip()` et `map()`.
Nous aimerions trouver quel est l'élément le plus petit en valeur absolue d'un vecteur donné.