Menu
Coddy logo textTech

Iterable & Iterator

Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 68 sur 110.

Chaque fois que vous utilisez une boucle for-in sur une List, un Set ou une autre collection, vous travaillez avec Iterable et Iterator sous le capot. Comprendre ces concepts vous permet de créer vos propres classes sur lesquelles il est possible d'itérer.

Un Iterable est n'importe quel objet capable de produire une séquence de valeurs. Il a une exigence clé : un getter iterator qui renvoie un Iterator. L'Iterator est ce qui parcourt réellement les éléments un par un :

var numbers = [1, 2, 3];
var iterator = numbers.iterator;

while (iterator.moveNext()) {
  print(iterator.current);  // 1, puis 2, puis 3
}

La méthode moveNext() passe à l'élément suivant et retourne true s'il y en a un, ou false lorsqu'elle a terminé. La propriété current vous donne l'élément actuel.

Pour rendre votre propre classe itérable, implémentez l'interface Iterable :

class Countdown extends Iterable<int> {
  final int start;
  Countdown(this.start);
  
  @override
  Iterator<int> get iterator => CountdownIterator(start);
}

class CountdownIterator implements Iterator<int> {
  int _current;
  
  CountdownIterator(int start) : _current = start + 1;
  
  @override
  int get current => _current;
  
  @override
  bool moveNext() {
    if (_current > 0) {
      _current--;
      return true;
    }
    return false;
  }
}

void main() {
  for (var n in Countdown(3)) {
    print(n);  // 3, 2, 1, 0
  }
}

Désormais, Countdown fonctionne avec les boucles for-in et toutes les méthodes Iterable telles que map, where et fold. Ce modèle est essentiel lors de la création de collections personnalisées qui s'intègrent parfaitement à l'écosystème de collections de Dart.

challenge icon

Défi

Facile

Construisons un générateur de plage personnalisé qui peut être parcouru à l'aide d'une boucle for-in ! Vous allez créer vos propres classes Iterable et Iterator pour générer une séquence de nombres dans une plage spécifiée.

Vous organiserez votre code en deux fichiers :

  • range.dart : Créez deux classes qui travaillent ensemble pour produire une séquence de nombres :
    • Une classe RangeIterator qui implémente Iterator<int>. Elle doit suivre la position actuelle et savoir quand s'arrêter. L'itérateur commence avant le premier élément, donc moveNext() doit être appelé avant d'accéder à current.
    • Une classe Range qui étend Iterable<int>. Elle prend une valeur start et end dans son constructeur et fournit un getter iterator qui retourne un RangeIterator.
    La plage doit inclure à la fois start et end. Par exemple, Range(1, 5) doit produire : 1, 2, 3, 4, 5.
  • main.dart : Importez votre fichier range et démontrez votre itérable personnalisé :
    • Créez un Range(1, 5) et utilisez une boucle for-in pour imprimer chaque nombre sur sa propre ligne
    • Imprimez une ligne vide
    • Créez un Range(10, 13) et utilisez la méthode map pour doubler chaque valeur, puis imprimez la liste résultante

Parce que votre classe Range étend Iterable, elle accède automatiquement à toutes les méthodes de collection puissantes comme map, where, et fold - c'est toute la beauté de l'implémentation de l'interface Iterable !

Sortie attendue :

1
2
3
4
5

[20, 22, 24, 26]

Aide-mémoire

Un Iterable est n'importe quel objet capable de produire une séquence de valeurs. Il nécessite un getter iterator qui renvoie un Iterator.

Un Iterator parcourt les éléments un par un en utilisant :

  • moveNext() - avance vers l'élément suivant et renvoie true s'il y en a un, ou false une fois terminé
  • current - propriété qui vous donne l'élément actuel

Utiliser un itérateur manuellement :

var numbers = [1, 2, 3];
var iterator = numbers.iterator;

while (iterator.moveNext()) {
  print(iterator.current);  // 1, puis 2, puis 3
}

Pour rendre une classe personnalisée itérable, implémentez l'interface Iterable et créez une classe Iterator correspondante :

class Countdown extends Iterable<int> {
  final int start;
  Countdown(this.start);
  
  @override
  Iterator<int> get iterator => CountdownIterator(start);
}

class CountdownIterator implements Iterator<int> {
  int _current;
  
  CountdownIterator(int start) : _current = start + 1;
  
  @override
  int get current => _current;
  
  @override
  bool moveNext() {
    if (_current > 0) {
      _current--;
      return true;
    }
    return false;
  }
}

void main() {
  for (var n in Countdown(3)) {
    print(n);  // 3, 2, 1, 0
  }
}

Les classes qui étendent Iterable fonctionnent avec les boucles for-in et accèdent automatiquement à toutes les méthodes Iterable telles que map, where et fold.

Essayez vous-même

import 'range.dart';

void main() {
  // TODO : Créer un Range(1, 5) et utiliser une boucle for-in pour afficher chaque nombre
  
  
  // TODO : Afficher une ligne vide
  
  
  // TODO : Créer un Range(10, 13), utiliser map pour doubler chaque valeur et afficher la liste
  
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet