Closures
Eine Funktion kann eine andere Funktion erstellen und zurückgeben, wie jeden anderen Wert. Die neue Funktion merkt sich dann die lokalen Variablen der Funktion, die sie erstellt hat, auch nachdem diese beendet ist. Hier ist eine Funktion, die Zähler herstellt:
local function erstelleZaehler()
local anzahl = 0
return function()
anzahl = anzahl + 1
return anzahl
end
end
local eierZaehler = erstelleZaehler()
print(eierZaehler())
print(eierZaehler())
print(eierZaehler())Das gibt Folgendes aus:
1
2
3Schritt für Schritt: erstelleZaehler() erstellt eine lokale Variable anzahl mit dem Wert 0, erstellt dann eine anonyme Funktion, gibt sie zurück und endet. Die zurückgegebene Funktion wird in eierZaehler gespeichert. Normalerweise verschwinden die lokalen Variablen einer Funktion, wenn sie endet, aber anzahl nicht: Die zurückgegebene Funktion benutzt sie, also behält Lua sie, solange diese Funktion existiert. Jeder Aufruf von eierZaehler() erhöht dieses anzahl und gibt es zurück.
Eine Funktion zusammen mit den Variablen, die sie sich merkt, heißt Closure. Jeder Aufruf von erstelleZaehler erstellt ein neues anzahl, also hat jeder Zähler sein eigenes:
local function erstelleZaehler()
local anzahl = 0
return function()
anzahl = anzahl + 1
return anzahl
end
end
local eier = erstelleZaehler()
local milch = erstelleZaehler()
eier()
eier()
milch()
print("Eier: " .. eier())
print("Milch: " .. milch())Das gibt Folgendes aus:
Eier: 3
Milch: 2eier() in einer eigenen Zeile ruft den Zähler auf und wirft die Zahl weg, die er zurückgibt; das ist erlaubt. Warum nicht einfach eine Variable außerhalb der Funktion benutzen? Dann könnte jeder Teil des Programms sie ändern, und für zwei Zähler bräuchtest du zwei Variablen und zwei Funktionen. In einer Closure ist anzahl versteckt: Nur der Zähler selbst kommt an sie heran.
Die Parameter der äußeren Funktion sind ebenfalls ihre lokalen Variablen, eine Closure merkt sich also auch sie:
local function erstelleVerkaeufer(preis)
return function(anzahl)
return anzahl * preis
end
end
local verkaufeKarotten = erstelleVerkaeufer(5)
local verkaufeKuerbisse = erstelleVerkaeufer(20)
print(verkaufeKarotten(10), verkaufeKuerbisse(3), verkaufeKarotten(2))Das gibt Folgendes aus:
50 60 10verkaufeKarotten merkt sich den Preis 5, und verkaufeKuerbisse merkt sich 20. Jede zurückgegebene Funktion hat ihr eigenes preis, das einmal gesetzt wurde, als sie hergestellt wurde.
So schreibst du es:
Anweisungen
- 1
Schreibe eine Funktion
erstelleZaehlermit einem Parameterschritt. Sie gibt eine neue Funktion zurück, die bei jedem Aufrufschrittzu ihrem eigenen Zählerstand addiert (er beginnt bei0) und den neuen Zählerstand zurückgibt. Füge darunter diesen Code hinzu:local eier = erstelleZaehler(6) local milch = erstelleZaehler(10) eier() eier() milch() print("Eier: " .. eier()) print("Milch: " .. milch())Emma sammelt Eier halbdutzendweise und Milch in 10-Liter-Kannen, also gibt das Programm Folgendes aus:
Eier: 18 Milch: 20 - 2
Schreibe eine Funktion
erstelleBudgetmit einem Parametermuenzen. Sie gibt eine Funktion mit einem Parameterpreiszurück: Istpreishöchstensmuenzen, zieht die Funktion ihn vonmuenzenab, und in jedem Fall gibt sie zurück, wie viele Münzen übrig sind. Emma und Opa Josef bekommen jeder ein eigenes Budget. Füge am Ende diesen Code hinzu:local emma = erstelleBudget(20) local josef = erstelleBudget(15) print(emma(8)) print(josef(4)) print(emma(5)) print(emma(10))Der letzte Einkauf kostet mehr, als Emma übrig hat, also findet er nicht statt. Das Programm gibt Folgendes aus:
12 11 7 7