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.
Aufgabe
EinfachLassen 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, dieIterator<int>implementiert. Sie sollte die aktuelle Position verfolgen und wissen, wann sie stoppen muss. Der Iterator beginnt vor dem ersten Element, daher mussmoveNext()aufgerufen werden, bevor aufcurrentzugegriffen wird. - Eine
Range-Klasse, dieIterable<int>erweitert. Sie nimmt einenstart- und einenend-Wert in ihrem Konstruktor entgegen und stellt eineniterator-Getter bereit, der einenRangeIteratorzurückgibt.
startals auchendeinschließen. Zum Beispiel sollteRange(1, 5)Folgendes erzeugen: 1, 2, 3, 4, 5.- Eine
main.dart: Importieren Sie Ihre Range-Datei und demonstrieren Sie Ihr benutzerdefiniertes Iterable:- Erstellen Sie ein
Range(1, 5)und verwenden Sie einefor-in-Schleife, um jede Zahl in einer eigenen Zeile auszugeben. - Geben Sie eine Leerzeile aus (
''). - Erstellen Sie ein
Range(10, 13)und verwenden Sie diemap-Methode, um jeden Wert zu verdoppeln, und geben Sie dann die resultierende Liste aus.
- Erstellen Sie ein
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 gibttruezurück, wenn eines vorhanden ist, oderfalse, wenn der Vorgang abgeschlossen istcurrent- 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
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor