Menu
Coddy logo textTech

Iterable & Iterator

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 68 von 110.

Jedes Mal, wenn Sie eine for-in-Schleife auf einer List, einem Set oder einer anderen Collection verwenden, arbeiten Sie im Hintergrund mit Iterable und Iterator. Das Verständnis dieser Konzepte ermöglicht es Ihnen, eigene Klassen zu erstellen, über die iteriert werden kann.

Ein Iterable ist jedes Objekt, das eine Sequenz von Werten erzeugen kann. Es hat eine wesentliche Voraussetzung: einen iterator-Getter, der einen Iterator zurückgibt. Der Iterator ist das, was sich tatsächlich nacheinander durch die Elemente bewegt:

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

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

Die Methode moveNext() rückt zum nächsten Element vor und gibt true zurück, wenn eines vorhanden ist, oder false, wenn der Vorgang abgeschlossen ist. Die Eigenschaft current liefert das aktuelle Element.

Um Ihre eigene Klasse iterierbar zu machen, implementieren Sie das Iterable-Interface:

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
  }
}

Jetzt funktioniert Countdown mit for-in-Schleifen und allen Iterable-Methoden wie map, where und fold. Dieses Muster ist essenziell beim Erstellen benutzerdefinierter Collections, die sich nahtlos in das Collection-Ökosystem von Dart integrieren.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen benutzerdefinierten Bereichsgenerator erstellen, der mit einer for-in-Schleife iteriert werden kann! Sie werden Ihre eigenen Iterable- und Iterator-Klassen erstellen, um eine Sequenz von Zahlen innerhalb eines bestimmten Bereichs zu generieren.

Sie werden Ihren Code in zwei Dateien organisieren:

  • range.dart: Erstellen Sie zwei Klassen, die zusammenarbeiten, um eine Sequenz von Zahlen zu erzeugen:
    • Eine RangeIterator-Klasse, die Iterator<int> implementiert. Sie sollte die aktuelle Position verfolgen und wissen, wann sie stoppen muss. Der Iterator beginnt vor dem ersten Element, daher muss moveNext() aufgerufen werden, bevor auf current zugegriffen wird.
    • Eine Range-Klasse, die Iterable<int> erweitert. Sie nimmt einen start- und einen end-Wert in ihrem Konstruktor entgegen und stellt einen iterator-Getter bereit, der einen RangeIterator zurückgibt.
    Der Bereich sollte sowohl start als auch end einschließen. Zum Beispiel sollte Range(1, 5) Folgendes erzeugen: 1, 2, 3, 4, 5.
  • main.dart: Importieren Sie Ihre Range-Datei und demonstrieren Sie Ihr benutzerdefiniertes Iterable:
    • Erstellen Sie ein Range(1, 5) und verwenden Sie eine for-in-Schleife, um jede Zahl in einer eigenen Zeile auszugeben.
    • Geben Sie eine Leerzeile aus ('').
    • Erstellen Sie ein Range(10, 13) und verwenden Sie die map-Methode, um jeden Wert zu verdoppeln, und geben Sie dann die resultierende Liste aus.

Da Ihre Range-Klasse Iterable erweitert, erhält sie automatisch Zugriff auf alle leistungsstarken Collection-Methoden wie map, where und fold – das ist das Schöne an der Implementierung des Iterable-Interfaces!

Erwartete Ausgabe:

1
2
3
4
5

[20, 22, 24, 26]

Spickzettel

Ein Iterable ist jedes Objekt, das eine Sequenz von Werten erzeugen kann. Es erfordert einen iterator-Getter, der einen Iterator zurückgibt.

Ein Iterator bewegt sich nacheinander durch die Elemente unter Verwendung von:

  • moveNext() - rückt zum nächsten Element vor und gibt true zurück, wenn eines vorhanden ist, oder false, wenn der Vorgang abgeschlossen ist
  • current - Eigenschaft, die das aktuelle Element liefert

Manuelle Verwendung eines Iterators:

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

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

Um eine benutzerdefinierte Klasse iterierbar zu machen, implementieren Sie das Iterable-Interface und erstellen Sie eine entsprechende Iterator-Klasse:

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
  }
}

Klassen, die Iterable erweitern, funktionieren mit for-in-Schleifen und erhalten automatisch Zugriff auf alle Iterable-Methoden wie map, where und fold.

Probier es selbst

import 'range.dart';

void main() {
  // TODO: Erstelle eine Range(1, 5) und verwende eine for-in-Schleife, um jede Zahl auszugeben
  
  
  // TODO: Gib eine Leerzeile aus
  
  
  // TODO: Erstelle eine Range(10, 13), verwende map, um jeden Wert zu verdoppeln, und gib die Liste aus
  
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung