... bis zum ersten nil-Element.
Ein Iterator ist ein Objekt, das verwendet werden kann, um einige oder alle Elemente in einem Container der Standard Template Library zu durchlaufen. Jedes Iteratorobjekt repräsentiert eine bestimmte Adresse im Container.
In Lua ist ein Iterator eine Struktur, die Zeigertypen unterstützt. Er kann jedes Element einer Sammlung durchlaufen.
Generic-for-Iterator
Generic for speichert die Iteratorfunktion intern. Tatsächlich speichert es drei Werte: die Iteratorfunktion, die Zustandskonstante und die Steuervariable.
Der Generic-for-Iterator liefert Schlüssel/Wert-Paare der Sammlung. Die Syntax ist wie folgt:
for k, v in pairs(t) do
print(k, v)
end
Im obigen Code sind k, v die Variablenliste; pairs(t) ist die Ausdrucksliste.
Betrachten Sie das folgende Beispiel:
Beispiel
for key,value in ipairs(array)
do
print(key, value)
end
Die Ausgabe der obigen Codeausführung ist:
1 Google 2 Example
Im obigen Beispiel haben wir die von Lua standardmäßig bereitgestellte Iteratorfunktion ipairs verwendet.
Nun sehen wir uns den Ausführungsablauf von Generic for an:
- Erstens, initialisieren: den Ausdruck nach `in` auswerten. Der Ausdruck sollte die drei Werte zurückgeben, die Generic for benötigt: die Iteratorfunktion, die Zustandskonstante und die Steuervariable. Wie bei einer Mehrfachzuweisung: Wenn der Ausdruck weniger als drei Werte zurückgibt, werden die fehlenden automatisch mit nil aufgefüllt und überzählige Werte ignoriert.
- Zweitens, die Iteratorfunktion mit der Zustandskonstante und der Steuervariable als Argumente aufrufen (Hinweis: für die for-Struktur ist die Zustandskonstante nutzlos; sie wird nur während der Initialisierung ermittelt und an die Iteratorfunktion übergeben).
- Drittens, die von der Iteratorfunktion zurückgegebenen Werte der Variablenliste zuweisen.
- Viertens: Wenn der erste zurückgegebene Wert nil ist, endet die Schleife; andernfalls wird der Schleifenkörper ausgeführt.
- Fünftens: Kehre zum zweiten Schritt zurück und rufe die Iteratorfunktion erneut auf.
In Lua verwenden wir häufig Funktionen, um Iteratoren zu beschreiben. Bei jedem Aufruf der Funktion gibt sie das nächste Element der Sammlung zurück. Lua-Iteratoren umfassen die folgenden zwei Typen:
- Zustandslose Iteratoren
- Iteratoren mit mehreren Zuständen
Zustandslose Iteratoren
Ein zustandsloser Iterator ist ein Iterator, der keinen Zustand beibehält. Daher können wir in Schleifen zustandslose Iteratoren verwenden, um die zusätzlichen Kosten für das Erstellen von Closures zu vermeiden.
In jeder Iteration wird die Iteratorfunktion mit den Werten zweier Variablen (der Zustandskonstante und der Steuervariablen) als Argumente aufgerufen. Ein zustandsloser Iterator kann das nächste Element allein mit diesen beiden Werten ermitteln.
Ein typisches und einfaches Beispiel für einen solchen zustandslosen Iterator ist ipairs, das jedes Element eines Arrays durchläuft, dessen Indizes numerisch sein müssen.
Das folgende Beispiel verwendet eine einfache Funktion, um einen Iterator zu implementieren, der das Quadrat einer Zahl n berechnet:
Beispiel
if currentNumber<iteratorMaxCount
dann
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,3,0
do
print(i,n)
end
Die Ausgabe des obigen Beispiels ist:
1 1 2 4 3 9
Der Iterationszustand umfasst die durchlaufene Tabelle (die Zustandskonstante, die sich während der Schleife nicht ändert) und den aktuellen Index (die Steuervariable). ipairs und die Iteratorfunktion sind beide sehr einfach. In Lua können wir es so implementieren:
Beispiel
i = i + 1
local v = a[i]
if v then
return i, v
end
end
function ipairs (a)
return iter, a, 0
end
Wenn Lua ipairs(a) aufruft, um die Schleife zu starten, erhält es drei Werte: die Iteratorfunktion iter, die Zustandskonstante a und den Anfangswert der Steuervariablen 0. Dann ruft Lua iter(a,0) auf und gibt 1, a zurück
Iteratoren mit mehreren Zuständen
In vielen Fällen müssen Iteratoren mehrere Zustandsinformationen speichern und nicht nur eine Zustandskonstante und eine Steuervariable. Die einfachste Methode ist die Verwendung von Closures. Eine andere Methode besteht darin, alle Zustandsinformationen in einer Tabelle zu kapseln und die Tabelle als Zustandskonstante des Iterators zu verwenden. In diesem Fall benötigt die Iteratorfunktion normalerweise keinen zweiten Parameter, da alle Informationen in der Tabelle gespeichert werden können.
Im folgenden Beispiel haben wir unseren eigenen Iterator erstellt:
Beispiel
function elementIterator (collection)
local index = 0
local count = #collection
-- Closure-Funktion
return function ()
index = index + 1
if index <= count
dann
-- aktuelles Element des Iterators zurückgeben
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Die Ausgabe des obigen Beispiels ist:
Google Example
Im obigen Beispiel können wir sehen, dass elementIterator eine Closure-Funktion verwendet, um die Größe der Sammlung zu berechnen und jedes Element auszugeben.
Weitere Erweiterungen