Iteratoren sind kein originelles Konzept in Ruby. Sie sind in objektorientierten Sprachen üblich. Wird auch in Lisp verwendet, obwohl sie nicht als Iteratoren bezeichnet werden. Das Konzept der Iteratoren ist jedoch vielen ungewohnt und muss daher näher erläutert werden.
Das Verb iterieren bedeutet, etwas oft zu tun, und Sie wissen, dass ein Iterator etwas ist, das etwas oft tut.
Wenn wir Code schreiben, müssen wir in vielen Situationen mit Schleifen arbeiten. In C verwenden wir * für * oder * while. * Zum Beispiel:
char *str; for (str = "abcdefg"; *str != '\0'; str++) { /* здесь идёт обработка символа */ }
In C bietet die * for (...) -Syntax eine Abstraktion, um beim Erstellen einer Schleife zu helfen, aber die Überprüfung von str * auf ein * Null-Zeichen * erfordert, dass der Programmierer die Details der internen Struktur des Strings kennt. Dies erweckt den Eindruck, dass C eine Low-Level-Sprache ist. Hochsprachen sind für ihre flexiblere Zeichenfolgenunterstützung bekannt. Betrachten Sie das folgende Shell-Skript sh*:
#!/bin/sh for i in *.[ch]; do # ... here would be something to do for each file done
Alle C-Quell- und Header-Dateien werden im aktuellen Verzeichnis verarbeitet, und der Shell-Befehl verarbeitet die Dateidetails, indem er die Dateinamen einzeln aufnimmt und ändert. Dieses Niveau ist höher als C, oder?
Aber es gibt noch mehr zu beachten: Während dies großartig für eine Sprache ist, die Iteratoren für integrierte Datentypen bereitstellt, sind wir frustriert, wenn wir wieder Low-Level-Schleifen für unsere eigenen Datentypen schreiben müssen. In OOP definieren Benutzer oft andere Datentypen, was ernsthafte Probleme verursachen kann.
Die objektorientierte Sprache beinhaltet also einige Möglichkeiten zur Iteration. Einige Sprachen bieten dafür spezielle Klassen an. Ruby ermöglicht es Ihnen, Iteratoren direkt zu definieren.
Ruby-String hat einige nützliche Iteratoren:
ruby> "abc".each_byte{|c| printf "<%c>", c}; print "\n" <a><b><c> nil
- jedes \ _byte * ist ein Iterator für jedes Zeichen in der Zeichenfolge. Jedes Zeichen wird in eine lokale Variable * c * gelegt. Dies könnte in etwas ähnliches wie C-Code übersetzt werden ...
ruby> s="abc";i=0 0 ruby> while i<s.length | printf "<%c>", s[i]; i+=1 | end; print "\n" <a><b><c> nil
... jedoch ist der Iterator * each \ _byte * konzeptionell einfacher und besser geeignet, um auch dann weiterzuarbeiten, wenn die Klasse String in Zukunft radikal modifiziert wird.Einer der Vorteile von Iteratoren besteht darin, dass sie robuster gegenüber solche Veränderungen. Was eigentlich eine gute Eigenschaft des Codes ist. (Ja, sei geduldig, wir werden mehr darüber sprechen, was Klassen sind)
Ein weiterer * String * Iterator ist * jede \ _line.
ruby> "a\nb\nc\n".each_line{|l| print l} a b c nil
Aufgaben, die C-Programmieraufwand erfordern (String-Trennzeichen finden, Teilstrings erstellen usw.) sind mit Iteratoren einfacher zu handhaben.
Die im vorigen Kapitel eingeführte * for-Anweisung * iteriert wie der Iterator * each . Die Zeichenfolge * each * funktioniert wie * each \ _line , schreiben wir das folgende Beispiel mit * für * neu:
ruby> for l in "a\nb\nc\n" | print l | end a b c nil
Wir können eine Kontrollstruktur * wiederholen * in Verbindung mit Schleifeniterationen verwenden, und dies wird die aktuelle Iteration an die Spitze der Schleifeniterationen zurückgeben.
ruby> c=0 0 ruby> for i in 0..4 | print i | if i == 2 and c == 0 | c = 1 | print "\n" | retry | end | end; print "\n" 012 01234 nil
Manchmal sehen Sie die Anweisung * yield * in einer Iteratordefinition. Yield verschiebt die Kontrolle an den Codeblock, der an den Iterator übergeben wurde (dies wird im Kapitel zur Objektbehandlung ausführlich behandelt). Das folgende Beispiel zeigt einen * Repeat * Iterator, der einen Codeblock so oft wiederholt, wie in einem Argument angegeben.
ruby> def repeat(num) | while num > 0 | yield | num -= 1 | end | end nil ruby> repeat(3) { print "foo\n" } foo foo foo nil
Mit retry können wir einen Iterator definieren, der wie eine while-Schleife funktioniert, obwohl dies zu langsam ist, um praktisch zu sein.
ruby> def WHILE(cond) | return if not cond | yield | retry | end nil ruby> i=0; WHILE(i<3) { print i; i+=1 } 012 nil
Verstehen Sie, was ein Iterator ist? Es gibt einige Einschränkungen für die ursprünglichen Iteratoren, aber tatsächlich ist es oft praktisch, geeignete Iteratoren zu definieren, wenn Sie einen neuen Datentyp definieren. In diesem Fall sind die obigen Beispiele nicht sehr hilfreich. Wir können darüber sprechen, wenn wir besser verstehen, was Klassen sind.