---
title: Cours de programmation séquentielle
subtitle: Itérateurs
author: Orestis Malaspinas
sansfont: Sans Serif
---

# Parcourir une liste

## Boucles `for`{.rust} (1/3)

On a déjà vu différentes façon de parcourir des collections:

1. La boucle `for`{.rust} sur un `Range`{.rust}

    ```{.lang-rust}
    let x = vec![1, 2, 3];
    for i in 0..3 { // Range
        println!("{}", x[i]);
    }
    ```
2. La boucle `for`{.rust} directement sur le vecteur

    ```{.lang-rust}
    let x = vec![1, 2, 3];
    for i in x { // Vec
        println!("{}", i);
    }
    ```

## Boucles `for`{.rust} (2/3)

- La syntaxe générale est

    ```{.lang-rust}
    for variable in expression {
        // do something
    }
    ```
- `expression`{.rust} est un **itérateur**: une série d'éléments.
- `variable`{.rust} prend à tour de rôle la valeur de chaque élément de l'itérateur.
- `variable`{.rust} peut être utilisé dans le bloc `for`{.rust}.

## Boucles `for`{.rust} (3/3)

Sans itérateurs on écrirait quelque chose du genre

```{.lang-rust}
let mut i = 0;
let x = vec![1, 2, 3];
while i < 3 {
    println!("{}", x[i]);
    i += 1;
}
```

# Les itérateurs

## Généralités

- Un **itérateur** est un objet sur lequel on peut appeler la méthode `.next()`{.rust}.
- La méthode `.next()`{.rust} est dans le trait `Iterator`.
- Lorsque `.next()`{.rust} est appelé l'itérateur retourne la prochaine valeur.
- Il se met dans l'état "suivant": il est **modifié**.
- `.next()`{.rust} retourne une `Option<T>`{.rust}.

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let mut r = 0..3;

    println!("{:?}", r.next()); // retourne?
    println!("{:?}", r.next()); // retourne?
    println!("{:?}", r.next()); // retourne?
    println!("{:?}", r.next()); // retourne?
    println!("{:?}", r.next()); // retourne?
}
</code></pre>

## Implémentation d'un itérateur

- La suite de Fibonacci:

$$
{\mathcal {F}}_{n+2}={\mathcal {F}}_{n+1}+{\mathcal {F}}_{n}
$$

<pre><code data-trim="hljs rust" class="lang-rust">
#[derive(Debug)]
struct Fib {
    act: usize, // nombre actuel
    prec: usize, // nombre précédent
}

impl Iterator for Fib {
    type Item = usize; // type de retour de l'itérateur
    
    fn next(&mut self) -> Option&lt;usize&gt; { // next retourne une option
        let new_act = self.act + self.prec;

        self.prec = self.act;
        self.act = new_act;

        Some(self.act) // la suite de Fibonacci est infinie, donc on retourne jamais None
    }
}

fn main() {
    let mut fib = Fib{act: 1, prec: 1};
    println!("{:?}", fib.next());

    let fib4 = fib.take(4); // retourne les 4 prochains éléments de l'itérateur
    for i in fib4 {
        println!("{}", i);
    }
}
</code></pre>

## Utilisations des itérateurs

- Un itérateur donne une séquence de valeurs.
- Un **adaptateur d'térateur** (iterator adapter) qui s'applique sur un itérateur produisant un nouvel itérateur.
- Un **consommateur** qui s'applique sur un adaptateur rendant un ensemble de valeurs et "détruisant" l'itérateur.

# Consommateur d'itérateur

Un consommateur "consomme" un itérateur et retourne une (ou un ensemble) de valeurs.
- `.collect()`{.rust}, `.find()`{.rust}, `.fold()`{.rust}, ...

## Exemples (1/2)

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let v = vec![0, 4, 7, 9, 15];

    let v_iter = v.iter();
    let sum: i32 = v_iter.sum(); // l'itérateur est détruit et on a calculé la somme des éléments
    println!("La somme est un consommateur: {}", sum);
    // println!("L'itérateur: {:?}", v_iter);
}
</code></pre>

## Exemples (2/2)

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let v = 0..10;
    let v_vec = v.collect::&lt;Vec&lt;i32&gt;&gt;(); // l'itérateur est détruit et transformé en Vec
    println!("Iter {:?}", v_vec);
    // println!("Range {:?}", v);
}
</code></pre>

# Adaptateur d'itérateur

Un adaptateur "adapte" un itérateur et retourne un itérateur.

## Exemples (1/2)

- `.map()`{.rust} prend une fonction anonyme (closure) en paramètre et l'applique à chaque élément.

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let v = vec![0, 4, 7, 9, 15];

    // iter() retourne un itérateur vers des références de v
    v.iter().map(|x| x + 1).map(|y| println!("{}", y)); // n'est pas consommé, rust ne fera rien ("lazy").
    let add_v: Vec&lt;i32&gt; = v.iter().map(|x| x + 1).collect();
    println!("{:?}", add_v);
}
</code></pre>

## Exemples (2/2)

- `.filter()`{.rust} prend prédicat et retourne un itérateur satisfaisant le prédicat.

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let v = vec![0, 4, 7, 9, 15];

    // into_iter() retourne un itérateur vers les valeurs de v (v disparaît)
    let fil_v: Vec&lt;i32&gt; = v.into_iter().filter(|x| *x > 7).collect();
    println!("{:?}", fil_v);
    // let fil_t2_v: Vec&lt;i32&gt; = v.into_iter().filter(|x| *x > 7).map(|y| 3*y).collect();
    // println!("{:?}", fil_v);
}
</code></pre>

