Lua-Tutorial

Bei Lua handelt es sich um eine in Brasilien Anfang der 90er-Jahre entwickelte Script-Sprache. Der Quelltext eines Lua-Programms wird vom Lua-Interpreter in Bytecode übersetzt und ausgeführt. Der Interpreter selbst ist in C geschrieben, was Lua-Programmen in der Ausführung zu hoher Performanz verhilft. Ferner ermöglicht das C-API es, Lua-Code in C/C++ Programmen einzubetten. Lua ist eine Multiparadigmensprache, die sich zum Schreiben von imperativem, funktionalem und objektorientiertem Code eignet.

Das stärkste Alleinstellungsmerkmal von Lua ist die einfache Einbettung in andere Systeme und Sprachen. Lua hat sich damit als „Glue Language“ etabliert und kommt in vielen Game-Engines zum Einsatz. Die Sprache lässt sich zudem zur Steuerung von Webservern wie Apache und nginx nutzen. Über die CGI-Schnittstelle wird Lua oft auch als eigenständige Internet-Programmiersprache verwendet. Ferner kommt die Sprache zur Entwicklung mobiler Apps zum Einsatz.

Lua Scripting Tutorial: Die ersten Schritte

Der einfachste und schnellste Weg, mit Lua programmieren zu lernen, besteht darin, Lua-Code auf der interaktiven Lua-Demo-Seite auszuführen. Sie können alle im weiteren Verlauf des Artikels dargestellten Lua-Code-Beispiele testen. Kopieren Sie eines der Code-Beispiele in das Textfeld und klicken Sie auf „run“, um den Code auszuführen.

Auf diesem Weg sparen Sie sich die Installation. Sollten Sie Lua auf dem eigenen System nutzen wollen, folgen Sie unseren weiteren Anweisungen. Andernfalls gehen Sie gleich weiter zum Abschnitt „Die Grundlagen der Lua-Scriptsprache erlernen“.

Das eigene System für das Lua-Tutorial vorbereiten

Der Lua-Interpreter besteht aus einer einzigen Binärdatei, die auf der Kommandozeile nach dem Befehl „lua“ bereitsteht. Diese wird auf dem System abgelegt und muss ggf. in den Pfad aufgenommen werden. Ferner bietet Lua Bibliotheken, die die Einbettung von Lua-Code in C/C++ Programmen ermöglichen.

Für die Installation unter Mac und Linux bietet sich die Installation mit dem „Homebrew“-Paketmanager an. Wenn Sie auf Ihrem System Homebrew installiert haben, nutzen Sie am besten den folgenden Befehl auf der Kommandozeile, um Lua zu installieren:

brew install lua

Um Lua auf einem Windows-System zu installieren bietet sich der LuaDist-Installer an.

Den Lua-Interpreter interaktiv nutzen

Wie bei vielen Script-Sprachen üblich, lässt sich der Lua-Interpreter interaktiv ausführen. Im interaktiven Modus nimmt der Interpreter auf der Kommandozeile Lua-Code entgegen und führt diesen zeilenweise aus. Die dabei erzeugte Werte werden direkt auf der Kommandozeile ausgegeben. Als Nutzer kann man dann die Werte von Variablen überprüfen und ändern. Somit eignet sich dieser Ansatz besonders zum schnellen Prototypisieren. Um den Lua-Interpreter im interaktiven Modus zu starten, führen wir auf der Kommandozeile den folgenden Befehl aus:

# Lua-Interpreter im interaktiven Modus starten
lua -i
Hinweis

Um den interaktiven Modus wieder zu verlassen, geben Sie den Befehl „os.exit()“ ein, oder drücken Sie die Tasten [Strg]+[D] in Kombination.

Lua-Script für das Tutorial mit dem Lua-Interpreter ausführen

Anstatt Lua-Code auf der Kommandozeile Stück für Stück einzugeben, können Sie den Lua-Interpreter auch anweisen, eine komplette Lua-Quelltextdatei auszuführen. Dafür erzeugen wir zunächst eine Lua-Datei und übergeben dem Lua-Interpreter den Dateinamen zur Ausführung. Der Interpreter liest den in der Datei enthaltenen Quelltext Zeile für Zeile ab und führt diesen aus.

# Lua-Script ausführen
lua <dateiname>.lua
Hinweis

Lua-Quelltextdateien enden mit der Dateierweiterung „.lua“.

Lua-Script für das Tutorial mittels Hashbang direkt ausführbar machen

Auf den Betriebssystemen Linux / UNIX / macOS haben wir auch die Möglichkeit, eine Lua-Quelltextdatei direkt ausführbar zu machen. Dazu tragen wir einen so genannten „Hashbang“ als erste Zeile der Lua-Datei ein:

#!/usr/local/bin/lua
-- Lua Code für die Ausführung

Wie Sie sehen, enthält der Hashbang den Speicherort der Lua-Binärdatei, in unserem Fall ‚#!/usr/local/bin/lua‘. Unter Umständen weicht der Speicherort auf Ihrem lokalen System davon ab. In diesem Fall können Sie den Speicherort der Lua-Binärdatei ermitteln. Nutzen Sie dazu den „which“-Befehl auf der Kommandozeile:

# Speicherort der Lua-Binärdatei ermitteln
which lua

Nachdem Sie ein Lua-Script mit dem Hashbang versehen haben, müssen Sie die Datei als durch den Nutzer ausführbar markieren. Nutzen Sie dafür den folgenden Befehl auf der Kommandozeile:

# Lua-Datei als ausführbar markieren
chmod u+rx <dateiname>.lua

Führen Sie das Lua-Script dann im aktuellen Verzeichnis aus:

./<dateiname>.lua
Tipp

Der Hashbang-Trick funktioniert auf Linux und UNIX-artigen Systemen wie macOS mit den meisten Script-Sprachen. Sie können nach dem selben Schema Ruby- oder Python-Scripte direkt ausführbar machen.

Die Grundlagen der Lua-Script-Sprache erlernen

Bei Lua handelt es sich um eine Multiparadigmensprache; der grundlegende Stil ist imperativ und funktional. Die Sprache ist komplett dynamisch, d.h. es wird keine Unterscheidung zwischen „compile time“ und „run time“ gemacht. Lua setzt ausnahmslos auf dynamische Speicherverwaltung: die Größe eines Objekts im Speicher kann sich während der Laufzeit ändern. Ein „Garbage Collector“ (GC) räumt nicht mehr benötigten Speicherplatz wieder frei, sodass der Programmierer sich nicht darum kümmern muss.

Kommentare in Lua-Scripten nutzen lernen

Kommentare sind essenzieller Bestandteil einer jeden Programmiersprache. Sie werden unter anderem für die folgenden Zwecke genutzt:

  • Code-Bestandteile skizzieren
  • Code-Features dokumentieren
  • Code-Zeilen aktivieren / deaktivieren

Ein einzeiliger Kommentar in Lua beginnt mit einem doppelten Bindestrich (--) und läuft bis zum Ende der Zeile:

-- diese Zeile wird vom Interpreter ignoriert

In Kombination mit doppelten eckigen Klammern „[[“ und „]]“ lassen sich auch mehrzeilige Kommentare schreiben:

--[[
Dieser Kommentar
erstreckt sich über
mehrere Zeilen.
]]

Werte und Typen für das Lua-Scripting-Tutorial

Wie die meisten anderen Script-Sprachen ist auch Lua eine dynamisch typisierte Sprache. Typen gehören nicht zu Variablen, sondern zu Werten. Jeder Wert hat genau einen Typ, sei es Zahl, Zeichenfolge, Wahrheitswert etc. Insgesamt verfügt Lua über eine überschaubare Anzahl an Typen. Diese sind in der folgenden Übersicht zusammengefasst:

Typ

Erklärung

number

Dezimalzahl

string

Zeichenfolge

boolean

Wahrheitswert: „true“ oder „false“

nil

Fehlender Wert; Typ hat nur den Wert „nil“

function

Funktion

table

Zusammengesetzter Datentyp: Liste / Array, Hash / Dictionary

thread

Coroutinen

userdata

Benutzer-definierter C-Datentyp

Lua kennt Literal-Syntax für Werte aller Typen mit Ausnahme von „thread“ und „userdata“. Um den Typ eines Werts zu ermitteln, nutzen wir die „type()“-Funktion. Diese gibt den Namen des Typs als String zurück. Hier ein paar Beispiele:

type(42) -- Typ ist `number`
type("Lua Tutorial") -- Typ ist `string`
type(false) -- Typ ist `boolean`
type(var) -- Typ ist `nil`, da `var` nicht definiert ist
Hinweis

Beachten Sie bei den folgenden Code-Beispielen, dass in Lua das erste Element einer Liste den Index 1 hat anstelle 0, wie in den meisten Sprachen üblich!

Mit Lua Programmieren lernen: Was sind Ausdrücke, Variablen und Operatoren?

Ein Ausdruck („Expression“) wird vom Interpreter evaluiert und liefert einen Wert zurück. Ausdrücke kombinieren Literale, Operatoren, Variablen und Funktionsaufrufe. Ausdrücke können optional mit Klammern „()“ gruppiert werden. Als dynamische Sprache ermittelt Lua den Typ des zurückgegebenen Werts automatisch. Hier einige Beispiele für Ausdrücke:

-- Arithmetische Operation in Lua
1 + 2 -- evaluiert zum Wert `3`
-- String-Konkatenation in Lua
'Walther' .. 'White' -- evaluiert zu `WaltherWhite`
-- String-Konkatenation mit automatischer Umwandlung einer Zahl in Lua
'Die ' .. 3 .. ' Musketiere' -- evaluiert zu `Die 3 Musketiere`
-- Gleichheits-Test in Lua
7 == '7' -- evaluiert zu `false`
-- Gleichheits-Test in Lua
'klein' == string.lower('KLEIN') -- evaluiert zu `true`
-- dynamische Typ-Information
type(var) == 'nil' -- evaluiert zu `true`, da `var` nicht definiert

Eine Variable ist ein Name für einen Wert im Speicher. Wie in den meisten Programmiersprachen beginnt ein Name in Lua mit einem Buchstaben oder Unterstrich (_), gefolgt von weiteren Buchstaben, Unterstrichen oder Zahlen. Dabei wird streng zwischen Groß- und Kleinschreibung unterschieden. Die folgenden reservierten Wörter dürfen für sich alleine nicht als Name verwendet werden:

„and“, „end“, „in“, „repeat“, „break“, „false“, „local“, „return“, „do“, „for“, „nil“, „then“, „else“, „function“, „not“, „true“, „elseif“, „if“, „or“, „until“, „while“

Allerdings können die reservierten Wörter problemlos als Teil eines Namens auftreten:

for = "Peter" -- ruft Fehler hervor
for_user = "Peter" -- erlaubt 

Die Zuweisung eines Werts an eine Variable erfolgt über den Zuweisungs-Operator (=). Nicht zu verwechseln ist dieser mit dem logischen Gleichheits-Operator (==). Bei der Zuweisung wird wie üblich zwischen „L-value“ und „R-value“ unterschieden: die Variable muss auf der linken Seite des Zuweisungs-Operators stehen, ist also der L-value. Diesem wird der evaluierte Wert des rechts stehenden R-value zugewiesen:

anzahl = 13 -- das ist OK
13 = anzahl -- ruft Fehler hervor, da der Zahl 13 kein neuer Wert zugewiesen werden kann

Ein Operator erzeugt einen neuen Wert aus einem oder mehreren Operanden. Dabei spricht man von einem unären (einstelligen) oder binären (zweistelligen) Operator. Ein Operator verknüpft Operanden eines bestimmten Typs und liefert einen Wert eines bestimmten Typs zurück. Schauen wir uns die verschiedenen Operatoren in Lua an.

Arithmetische Operatoren operieren auf Zahlen und liefern eine Zahl zurück:

Arithmetische Operator

Arität

Operation

+

binär

Addition

-

binär

Subtraktion

*

binär

Multiplikation

/

binär

Division

%

binär

Modulus

^

binär

Potenzierung

-

unär

Negation

Die relationalen Operatoren sind allesamt binär und testen, wie sich zwei Operanden zueinander verhalten. Sie liefern einen Wahrheitswert zurück:

Relationaler Operator

Test

==

Gleichheit

~=

Ungleichheit

>

Größer als

<

Kleiner als

>=

Größer als oder gleich

<=

Kleiner als oder gleich

Logische Operatoren verknüpfen Wahrheitswerte und liefern einen neuen Wahrheitswert zurück:

Logischer Operator

Arität

Operation

and

binär

UND-Verknüpfung

or

binär

ODER-Verknüpfung

not

unär

Negation

Neben den genannten gibt es noch zwei spezielle Operatoren in Lua. Diese dienen zur Konkatenation von Strings (also ihrer Verkettung) sowie zur Ermittlung der Mächtigkeit eines zusammengesetzten Werts, wie Table oder String:

Operator

Arität

Operation

..

binär

String-Konkatenation

#

unär

Anzahl Elemente eines Tables / Länge eines Strings ermitteln

Lua kennt keine zusammengesetzten Zuweisungs-Operatoren wie „+=“ und „-=“, die in vielen Script-Sprachen üblich sind. Zum Inkrementieren und Dekrementieren von Variablen wird die Operation explizit ausgeschrieben:

preis = 42.99
rabatt = 0.15 -- 15% Rabatt
preis -= preis * rabatt -- `-=` funktioniert in Lua nicht
-- Dekrementierung muss stattdessen explizit geschrieben werden
preis = preis - (preis * rabatt)

Gültigkeitsbereiche und Blöcke für das Lua Script-Tutorial verstehen

Das Konzept des Gültigkeitsbereichs ist ein zentrales Konzept einer jeden Programmiersprache. Eine Variable existiert nur innerhalb eines bestimmten Gültigkeitsbereichs. Wie in JavaScript sind Variablen in Lua per Voreinstellung global. Jedoch ist die durchgehende Nutzung globaler Variablen als „Anti-Pattern“ bekannt und sollte vermieden werden. In Lua schafft das „local“-Schlüsselwort Abhilfe. Mit diesem wird der Gültigkeitsbereich einer Variable auf den umgebenden Block beschränkt – vergleichbar mit der Deklaration via „let“ in JavaScript.

-- diese Variable ist global
x = 5
-- lokale Variable definieren
local z = 10

Die Körper von Funktionen und Schleifen öffnen in Lua einen neuen Gültigkeitsbereich. Ferner nutzt Lua das Konzept des expliziten Blocks. Ein Block definiert einen neuen Gültigkeitsbereich für den zwischen den Schlüsselwörtern „do“ und „end“ stehenden Code. Dies entspricht den öffnenden/schließenden Klammern „{“ und „}“ in Java/C/C++. Das folgende Code-Beispiel verdeutlicht, wie Blöcke, Gültigkeitsbereiche und Variablen zusammenhängen:

-- äußerer Gültigkeitsbereich
do
  local x = 1
  do -- innerer Gültigkeitsbereich
    local y = 2
    -- `z` im globalen Gültigkeitsbereich erzeugen
    -- dabei Zugriff auf lokale Variable `x` von äußerem Gültigkeitsbereich
    -- sowie lokale Variable `y` vom inneren Gültigkeitsbereich
    z = x + y -- `z` hat jetzt den Wert `3`
  end
  print(x) -- gibt `1` aus
  print(y) -- gibt `nil` aus, da `y` im äußeren Gültigkeitsbereich nicht existiert
  print(z) -- gibt `3` aus
end
-- `z` ist global, existiert also außerhalb des äußeren Gültigkeitsbereich
z = z + 4
print(z) -- gibt `7` aus

Mit den Lua-Kontrollstrukturen Programmieren lernen

Lua kennt die üblichen Kontrollstrukturen, die man auch in anderen Programmiersprachen findet. Dazu gehören die Verzweigungen und Schleifen. Hier ein Beispiel für Luas „if“-, „then“-, „else“-, „elseif“-Anweisungen:

limit = 42;
zahl = 43;
if zahl < limit then
  print("Unter dem Limit.")
elseif zahl == limit then
  print("Genau am Limit…")
else
  print("Über dem Limit!")
end

Neben der klassischen „while“-Schleife erkennt Lua auch deren Gegenstück „repeat“-„until“. Diese Anweisung findet man auch in Ruby. Sie erfordert die Umkehrung der eingesetzten Kondition. Das heißt, ein „while“ mit Kondition „zahl </= limit“ entspricht einem „repeat“-„until“ mit Kondition „zahl > limit“. Vorsicht mit der „repeat“-Anweisung! Unabhängig von der Kondition wird der Schleifenkörper mindestens einmal ausgeführt. Hier ein Beispiel:

limit = 10
zahl = 1
while zahl <= limit do
  print("Zahl:", zahl)
  zahl = zahl + 1
end
-- Achtung: obwohl `zahl` bereits größer als `limit`
-- wird der Schleifenkörper einmal ausgeführt
zahl = 11
repeat 
  print("Zahl:", zahl)
  zahl = zahl + 1
until zahl > limit

So wie die meisten imperativen Programmiersprachen kennt auch Lua neben der „while“-Schleife eine „for“-Anweisung. Dabei kommen zwei Formen zum Einsatz: eine C-ähnliche Variante mit Schleifen-Variable sowie eine Variante mit Iterator. Betrachten wir zunächst die Nutzung der „for“-Anweisung mit Schleifen-Variable:

anfang = 1
ende = 10
for zahl = anfang, ende do
  print("Aktuelle Zahl:", zahl) -- `1,2,3,4,5,6,7,8,9,10`
end
-- explizit Schritt auf `2` setzen
schritt = 2
for zahl = anfang, ende, schritt do
  print("Aktuelle Zahl:", zahl) -- `1,3,5,7,9`
end
-- der Schritt kann auch negativ sein
schritt = -2
-- mit negativem Schritt Anfang und Ende vertauschen, um absteigend zu zählen
for zahl = ende, anfang, schritt do
  print("Aktuelle Zahl:", zahl) -- `10,8,6,4,2`
end

Überraschenderweise ist die in der „for“-Schleife definierte Schleifen-Variable lokal, nicht global, ohne dass sie explizit als „local“ deklariert werden müsste. Das ist sinnvoll, und diesbezüglich unterscheidet sich Lua positiv von JavaScript. Dort ist eine ohne „let“ oder „var“ deklarierte Schleifen-Variable global, was zu schwerwiegenden Fehlern führen kann.

Schauen wir uns nun Luas „for“-Schleife mit Iterator an. Prinzipiell ähnelt der Ansatz dem von Python: Anstatt eine Schleifen-Variable zu inkrementieren und als Index in einer Liste zu nutzen, iterieren wir direkt über den Elementen der Liste. Zum Erzeugen des Iterators kommt häufig die „ipairs()“-Funktion zum Einsatz. Hier ein Beispiel:

-- Liste von Jahren definieren
dekaden = {1910, 1920, 1930, 1940, 1950, 1960, 1970, 1980, 1990}
-- mittels Iterator auf die einzelnen Jahre zugreifen
for index, jahr in ipairs(dekaden) do
  print(index, jahr)
end

Mehr über Funktionen mit Lua lernen

Funktionen werden wie in C/C++, Java und JavaScript mit dem „function“-Schlüsselwort definiert. Wie üblich folgen die Funktionsparameter in Klammern nach den Funktionsnamen. Das Besondere bei Lua ist, dass beim Funktionsaufruf mit genau einem Literal als Argument die Klammern weggelassen werden dürfen. Eine Lua-Funktion muss nicht zwingend einen Wert zurückgeben. Der Definition nach handelt es sich ohne Wert um eine „Prozedur“:

-- Prozedur definieren
function hallo(name)
  print("Guten Tag", name)
end
-- Funktion aufrufen
hallo("der feine Herr")
-- auch dies ist möglich
hallo "der feine Herr"
-- folgendes funktioniert jedoch nicht
name = "Walther"
hallo name -- Syntax-Fehler
-- mit Variable statt Literal muss die Funktion mit Klammern aufgerufen werden
hallo(name)

Will man aus einer Funktion einen Wert zurückzugeben, kommt wie üblich das „return“-Schlüsselwort zum Einsatz. Dieses beendet die Ausführung der Funktion und gibt den angegebenen Wert zurück. In folgendem Code-Beispiel wird eine Zahl quadriert:

-- Funktion mit einzelnem Rückgabewert
function quadrat(zahl)
  -- der Ausdruck `zahl * zahl` wird evaluiert
  -- und sein Wert zurückgegeben
  return zahl * zahl
end
-- Zahl quadrieren
print(quadrat(9)) -- `81`

Wie in Python und JavaScript kann eine Funktion in Lua eine variable Anzahl von Argumenten entgegennehmen. Die Argumente werden im speziellen Konstrukt „(...)“ gespeichert. Um auf die Argumente zuzugreifen, ist es oft nützlich, diese mit dem Ausdruck „{...}“ in einer Liste zusammenzufassen. Alternativ kommt die „select()“-Funktion zum Einsatz, die ein Argument unter dem angegebenen Index extrahiert. Die Anzahl der Argumente ermitteln wir mit dem Ausdruck „#{...}“.

-- alle Argumente einer Funktion drucken
function var_args(...)
  for index, arg  in ipairs({...}) do
    print(index, arg)
  end
end
var_args('Peter', 42, true)

Neben der variablen Anzahl von Argumenten erlaubt Lua auch, mehrere Werte mit einer „return“-Anweisung zurückzugeben. Dies funktioniert ähnlich wie in Python, jedoch ohne expliziten „Tupel“-Typ. Wie in Python ist es üblich, die Rückgabewerte beim Funktionsaufruf mehreren Variablen zuzuweisen. Hier ein Beispiel:

-- Funktion mit mehreren Rückgabewerten
function erster_und_letzter(liste)
  -- erstes und letztes Element der Liste zurückgeben
  -- einzelne Rückgabewerte werden durch ein Komma `,` getrennt
  return liste[1], liste[#liste]
end
leute = {"Jim", "Jack", "John"}
-- Zuweisung der Rückgabewerte an mehrere Variablen
erster, letzter = erster_und_letzter(leute)
print("Der erste ist", erster)
print("Der letzte ist", letzter)

Wird einer der Rückgabewerte nicht benötigt, nutzt man der gängigen Konvention folgend den Unterstrich (_) als Platzhalter, wie im folgenden Beispiel dargestellt:

function min_mittel_max(...)
  -- Anfangswerte für `min` und `max` auf erstes Argument setzen
  local min = select(1, ...)
  local max = select(1, ...)
  -- Mittelwert anfangs auf null setzen
  local mittel = 0
  -- über den Zahlen iterieren
  -- die Index-Variable benötigen wir nicht
  -- und nutzen daher `_` als Platzhalter
  for _, zahl  in ipairs({...}) do
    -- ggf. neues Minimum setzen
    if min > zahl then
      min = zahl
    end
    -- ggf. neues Maxiumum setzen
    if max < zahl then
      max = zahl
    end
    -- für den Durchschnitt Zahlen summieren
    mittel = mittel + zahl
  end
  -- Summe der Zahlen durch deren Anzahl teilen
  mittel = mittel / #{...}
  return min, mittel, max
end
-- hier benötigen wir den `mittel`-Wert nicht
-- und nutzen daher `_` als Platzhalter
min, _, max = min_mittel_max(78, 34, 91, 7, 28)
print("Minimum und Maximum der Zahlen sind", min, max)

Funktionen sind in Lua „first-class citizens“. Das heißt, sie können an Variablen gebunden werden und lassen sich damit auch als Argumente an andere Funktionen übergeben. Ferner kann eine Funktion als Rückgabewert einer Funktion dienen. Zusammengenommen ermöglicht Lua damit funktionale Programmierung, hier dargestellt am Beispiel der berühmten „map()“-Funktion:

-- `map()`-Funktion in Lua
-- nimmt eine Funktion `f` und eine Liste als Argumente entgegen
function map(f, liste)
  -- neue Liste für Ausgabewerte anlegen
  local _liste = {}
  -- über den Elementen der Liste mit Index iterieren
  for index, wert in ipairs(liste) do
    -- Funktion `f()` auf den aktuellen Wert der Liste anwenden
    -- und den Rückgabewert in neuer Liste am selben Index speichern
    _liste[index] = f(wert)
  end
  -- neue Liste zurückgeben
  return _liste
end
-- Liste von Zahlen
zahlen = {3, 4, 5}
-- Funktion, die auf alle Elemente der Liste angewandt wird
function quadrat(zahl)
  return zahl * zahl
end
-- erzeugen der Quadrate via `map()`-Funktion
quadrate = map(quadrat, zahlen) -- `{9, 16, 25}`
-- quadrierte Zahlen ausgeben
for _, zahl in ipairs(quadrate) do
  print(zahl)
end

In der funktionalen Programmierung wird oft Rekursion genutzt: Eine Funktion ruft sich selber mit veränderten Argumenten immer wieder auf. Dabei müssen wir bei Lua besondere Vorsicht walten lassen. Funktionen, die rekursiv aufgerufen werden, sollte man explizit als „local“ deklarieren.

function f()
  -- rekursiver Aufruf
  f() -- verweist ggf. auf globale Variable `f`
end
-- stattdessen
local function f()
  -- rekursiver Aufruf
  f() -- verweist auf die umgebende Funktion
end
-- equivalent zu
local f; -- Variable `f` explizit als `local` deklarieren
f = function() -- Zuweisung der Funktion an die lokale Variable `f`
  f() -- verweist garantiert auf die umgebende Funktion
end