Tables, Metatables & Module
Tables als universelle Datenstruktur, Metatables fuer OOP und Operator-Overloading, sowie require und eigene Module schreiben.
Inhaltsverzeichnis
Tables, Metatables & Module
Tables sind Luaโs einzige komplexe Datenstruktur - aber eine extrem flexible. Mit Metatables baust du darauf OOP und alles andere.
Tables - eine Kurzauffrischung
-- Array
local arr = {10, 20, 30}
-- Dictionary
local dict = {name = "Anna", alter = 28}
-- Gemischt
local mix = {"Max", age = 34, "Anna"}
print(mix[1]) -- "Max"
print(mix[2]) -- "Anna" (der Name "age=34" zaehlt nicht zum Array)
print(mix.age) -- 34
Table-Operationen
local t = {10, 20, 30}
t[4] = 40 -- hinzufuegen per Index
table.insert(t, 50) -- am Ende
table.insert(t, 1, 5) -- am Anfang (Index 1)
table.remove(t) -- letztes entfernen
table.remove(t, 1) -- bei Index 1 entfernen
#t -- Laenge des Array-Teils
table.concat(t, ", ") -- zu String verbinden: "5, 10, 20, 30, 40, 50"
table.sort(t) -- in-place sortieren
table.sort mit Comparator
local personen = {
{name = "Max", alter = 34},
{name = "Anna", alter = 28},
{name = "Leo", alter = 22}
}
table.sort(personen, function(a, b) return a.alter < b.alter end)
for _, p in ipairs(personen) do
print(p.name, p.alter)
end
-- Leo 22
-- Anna 28
-- Max 34
Verschachtelt
local team = {
leitung = { name = "Anna", rolle = "PM" },
mitglieder = {
{ name = "Max", skills = {"Go", "Rust"} },
{ name = "Leo", skills = {"Python", "React"} }
}
}
print(team.leitung.name)
print(team.mitglieder[1].skills[1]) -- "Go"
Referenzsemantik
Tables werden per Referenz uebergeben:
local a = {1, 2, 3}
local b = a -- b zeigt auf dasselbe Table
b[1] = 99
print(a[1]) -- 99 (a wurde mit geaendert!)
Fuer eine Kopie brauchst du eine explizite Funktion:
local function kopie(t)
local neu = {}
for k, v in pairs(t) do
neu[k] = v
end
return neu
end
(Das ist eine flache Kopie. Fuer tief-verschachtelte Strukturen brauchst du rekursive Logik oder eine Library.)
Metatables - die Magie
Eine Metatable ist ein Table, das einer anderen Table ein spezielles Verhalten gibt. Du legst Meta-Methoden ueber Keys wie __index, __add, __tostring fest.
Beispiel: __index fuer Default-Werte
local standard = { farbe = "rot", groesse = "mittel" }
local auto = setmetatable(
{ marke = "VW" },
{ __index = standard }
)
print(auto.marke) -- "VW"
print(auto.farbe) -- "rot" (aus standard!)
Wenn ein Key im Table nicht existiert, sucht Lua in der Metatableโs __index.
Beispiel: __tostring
local punkt = setmetatable(
{x = 3, y = 4},
{
__tostring = function(p)
return "(" .. p.x .. ", " .. p.y .. ")"
end
}
)
print(punkt) -- "(3, 4)"
Operator-Overloading mit __add
local function Vec2(x, y)
return setmetatable(
{x = x, y = y},
{
__add = function(a, b) return Vec2(a.x + b.x, a.y + b.y) end,
__tostring = function(v) return "(" .. v.x .. ", " .. v.y .. ")" end
}
)
end
local a = Vec2(1, 2)
local b = Vec2(3, 4)
print(a + b) -- "(4, 6)"
Klassen mit Metatables
Das Standardmuster fuer OOP:
local Person = {}
Person.__index = Person -- wenn Instanz-Feld fehlt, in Person suchen
function Person.new(name, alter)
local self = setmetatable({}, Person)
self.name = name
self.alter = alter
return self
end
function Person:gruessen()
print("Hallo, ich bin " .. self.name .. "!")
end
function Person:geburtstag()
self.alter = self.alter + 1
end
local anna = Person.new("Anna", 28)
anna:gruessen() -- "Hallo, ich bin Anna!"
anna:geburtstag()
print(anna.alter) -- 29
Was passiert da?
setmetatable({}, Person)- die neue Instanz schaut bei unbekannten Keys inPerson- Methoden mit
function Person:name(...)bekommen automatischselfals ersten Parameter - Der Aufruf
anna:gruessen()wird zugruessen(anna)
Vererbung
local Entwickler = setmetatable({}, {__index = Person})
Entwickler.__index = Entwickler
function Entwickler.new(name, alter, sprache)
local self = Person.new(name, alter)
setmetatable(self, Entwickler)
self.sprache = sprache
return self
end
function Entwickler:coden()
print(self.name .. " schreibt " .. self.sprache)
end
local max = Entwickler.new("Max", 34, "Lua")
max:gruessen() -- geerbt
max:coden() -- eigene Methode
Module schreiben und laden
Ein eigenes Modul
Lege mathe.lua an:
local M = {}
function M.addieren(a, b)
return a + b
end
function M.quadrat(n)
return n * n
end
M.PI = 3.14159
return M
Das Modul ist einfach eine Table, die zurueckgegeben wird.
Einbinden mit require
-- main.lua
local mathe = require("mathe") -- ohne .lua
print(mathe.addieren(3, 4)) -- 7
print(mathe.quadrat(5)) -- 25
print(mathe.PI) -- 3.14159
Wichtig:
- Der Modul-Name entspricht dem Dateinamen ohne
.lua requirecached Module - mehrfachesrequirelaedt die Datei nur einmal- Unterordner:
require("utils.mathe")fuerutils/mathe.lua
package.path
Wo sucht require nach Modulen? In package.path:
print(package.path)
Du kannst erweitern, z.B. fuer ein lib/-Verzeichnis:
package.path = package.path .. ";./lib/?.lua"
Standard-Libraries
Lua hat eine kleine, aber nuetzliche Standard-Library:
string- String-Methoden (format,sub,gsub, โฆ)table- Table-Methoden (insert,remove,concat,sort)math- Mathematik (pi,sqrt,random, โฆ)io- Ein-/Ausgabe (open,read,write)os- Betriebssystem (time,date,exit)
Dateien lesen und schreiben
-- Lesen
local f = io.open("daten.txt", "r")
if f then
local inhalt = f:read("*all")
f:close()
print(inhalt)
end
-- Schreiben
local f = io.open("ausgabe.txt", "w")
f:write("Hallo, Datei!\n")
f:close()
Praktisches Beispiel: Bibliothek
bibliothek.lua:
local M = {}
local Buch = {}
Buch.__index = Buch
function Buch.new(titel, autor)
return setmetatable(
{titel = titel, autor = autor, ausgeliehen = false},
Buch
)
end
function Buch:info()
local status = self.ausgeliehen and "ausgeliehen" or "verfuegbar"
return string.format("%s - %s (%s)", self.titel, self.autor, status)
end
function Buch:ausleihen()
if self.ausgeliehen then return false end
self.ausgeliehen = true
return true
end
function Buch:zurueckgeben()
self.ausgeliehen = false
end
M.Buch = Buch
return M
main.lua:
local bib = require("bibliothek")
local b1 = bib.Buch.new("1984", "Orwell")
local b2 = bib.Buch.new("Die Verwandlung", "Kafka")
print(b1:info())
b1:ausleihen()
print(b1:info())
b1:zurueckgeben()
print(b1:info())
Zusammenfassung
- Tables sind Array + Dictionary + Objekt in einem
- Metatables geben Tables spezielles Verhalten (
__index,__add,__tostring, โฆ) Person.__index = Person+setmetatableist das OOP-Standardmuster- Vererbung via verschachtelte Metatables
- Eigene Module: Table anlegen, Funktionen reinhaengen,
returnam Ende requirelaedt Module und cached sie- Standard-Library:
string,table,math,io,os
Damit hast du Luaโs Kern im Griff. Im weiteren Kurs vertiefen wir Coroutines, Metaprogramming und den Einsatz in Roblox/Neovim.