Menu
Coddy logo textTech

Iterator-Muster

Teil des Abschnitts Object Oriented Programming der Lua-Journey von Coddy — Lektion 64 von 70.

Wenn Sie eine Sammlung von Elementen haben, die in einem Objekt gespeichert sind, möchten Sie diese oft durchlaufen. Luas generische for-Schleife funktioniert hervorragend mit benutzerdefinierten Iteratoren, und Sie können diese Funktionalität direkt in Ihre Klassen einbauen.

Das Iterator-Muster ermöglicht es einem Objekt zu steuern, wie seine internen Daten durchlaufen werden. Ein eleganter Ansatz verwendet die __call-Metamethode, die ein Objekt wie eine Funktion aufrufbar macht. Jeder Aufruf gibt das nächste Element zurück, bis keine weiteren mehr vorhanden sind.

local Collection = {}
Collection.__index = Collection

function Collection:new()
    local obj = { items = {}, index = 0 }
    setmetatable(obj, Collection)
    return obj
end

function Collection:add(item)
    table.insert(self.items, item)
end

function Collection:__call()
    self.index = self.index + 1
    return self.items[self.index]
end

Mit __call definiert, können Sie mit einer while-Schleife iterieren oder das Objekt direkt an ein generisches for übergeben:

local bag = Collection:new()
bag:add("apple")
bag:add("banana")

for item in bag do
    print(item)
end

Die Schleife ruft bag() wiederholt auf. Wenn __call den Wert nil zurückgibt (keine weiteren Elemente), stoppt die Schleife. Dieses Muster kapselt die Iterationslogik innerhalb des Objekts selbst und gibt Ihnen die volle Kontrolle darüber, wie – und in welcher Reihenfolge – auf Elemente zugegriffen wird.

challenge icon

Aufgabe

Einfach

Lassen Sie uns eine Playlist-Klasse erstellen, die Sie mit Luas generischer for-Schleife durchlaufen können! Sie werden das Iterator-Muster unter Verwendung der __call-Metamethode implementieren, sodass Ihre Playlist Song für Song durchlaufen werden kann.

Sie werden Ihren Code auf zwei Dateien aufteilen:

  • Playlist.lua: Erstellen Sie eine Playlist-Klasse, die Songs intern speichert. Ihre Klasse benötigt einen :new()-Konstruktor, der eine leere Songliste initialisiert und den Iterationsindex auf 0 setzt. Fügen Sie eine :addSong(title)-Methode hinzu, um Songs zur Playlist hinzuzufügen. Am wichtigsten ist, dass Sie die __call-Metamethode implementieren, sodass jedes Mal, wenn die Playlist „aufgerufen“ wird, der nächste Song in der Liste zurückgegeben wird (oder nil, wenn keine Songs mehr vorhanden sind).
  • main.lua: Binden Sie Ihr Playlist-Modul ein und erstellen Sie eine neue Playlist. Fügen Sie Songs basierend auf den empfangenen Eingaben hinzu und verwenden Sie dann eine generische for-Schleife, um die Playlist zu durchlaufen und jeden Songtitel in einer eigenen Zeile auszugeben.

Das Besondere am Iterator-Muster ist, dass Ihr Playlist-Objekt aufrufbar wird – wenn es in einer for-Schleife verwendet wird, ruft Lua es wiederholt auf, bis es nil zurückgibt, wodurch Sie jeden Song nacheinander erhalten.

Sie erhalten drei Eingaben, die jeweils einen Songtitel darstellen, der Ihrer Playlist (in der entsprechenden Reihenfolge) hinzugefügt werden soll.

Wenn die Eingaben beispielsweise Bohemian Rhapsody, Stairway to Heaven und Hotel California sind, sollte die Ausgabe wie folgt aussehen:

Bohemian Rhapsody
Stairway to Heaven
Hotel California

Wenn die Eingaben Yesterday, Imagine und Let It Be sind, sollte die Ausgabe wie folgt aussehen:

Yesterday
Imagine
Let It Be

Spickzettel

Das Iterator-Muster ermöglicht es einem Objekt zu steuern, wie seine internen Daten durchlaufen werden, indem eine benutzerdefinierte Iterationslogik implementiert wird.

Verwenden Sie die Metamethode __call, um ein Objekt wie eine Funktion aufrufbar zu machen. Jeder Aufruf gibt das nächste Element zurück, bis keine weiteren mehr vorhanden sind (gibt nil zurück):

local Collection = {}
Collection.__index = Collection

function Collection:new()
    local obj = { items = {}, index = 0 }
    setmetatable(obj, Collection)
    return obj
end

function Collection:add(item)
    table.insert(self.items, item)
end

function Collection:__call()
    self.index = self.index + 1
    return self.items[self.index]
end

Wenn __call definiert ist, können Sie das Objekt direkt in einer generischen for-Schleife verwenden:

local bag = Collection:new()
bag:add("apple")
bag:add("banana")

for item in bag do
    print(item)
end

Die Schleife ruft das Objekt wiederholt auf. Wenn __call den Wert nil zurückgibt, stoppt die Schleife automatisch.

Probier es selbst

-- Erfordert das Playlist-Modul
local Playlist = require('Playlist')

-- Drei Songtitel von der Eingabe lesen
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()

-- TODO: Erstelle eine neue Playlist mit Playlist:new()

-- TODO: Füge die drei Songs mit :addSong() zur Playlist hinzu

-- TODO: Verwende eine generische for-Schleife, um durch die Playlist zu iterieren
-- und gib jeden Songtitel in einer eigenen Zeile aus
-- Hinweis: for song in playlist do ... end
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 Object Oriented Programming