Ein Metatable ist technisch erst mal nichts anderes als ein normales Table. Jeder Wert in Lua kann ein Metatable besitzen. Mit einem Metatable kann man jedoch das Verhalten von einem Wert in bestimmten Situationen beeinflussen.
Das Thema ist für den Anfang recht komplex und nicht so leicht nachvollziehbar. Für den Anfang muss man das alles nicht 100%ig verstehen. Aber man sollte grundsätzlich wissen, dass es diese Option gibt, was man damit machen kann und wie es verwendet wird.

Also was genau macht ein Metatable? Ein Metatable stellt Funktionen bereit, die man selbst definieren kann. Möchte man, dass ein Table sich bei einer Addition anders verhält, kann man das damit bewerkstelligen. Wenn zum Beispiel ein Wert Teil einer Addition ist, dann schaut Lua automatisch erst Mal, ob es eine Funktion im __add-Feld des Metatables gibt. Und wenn es dort etwas zu tun gibt, wird es ausgeführt.

Es gibt verschiedene Funktionen, die wir innerhalb des Metatables definieren können. Diese Funktionen werden in diesem Zusammenhang Methoden genannt. Jeder Methodenname beginnt mit zwei Unterstrichen.

__add steht für Addition
__sub für Subtraktion
__mul für Multiplikation

Und so weiter und so fort. Eine komplette Liste gibt es hier. Es gibt aber nicht nur Methoden für mathematische Operationen. Damit wir besser verstehen, was wir damit machen können, schauen wir uns mal ein kleines Beispiel an:

local testtable = {}
print(testtable[1])

In der Konsole wird nun der Wert nil ausgegeben, da dieses Feld nicht definiert ist. Was der Lua-Interpreter nun aber noch tut, ohne es uns zu sagen, ist, dass er nach einer Metamethode namens __index sucht. Diese Funktion würde er nun stattdessen ausführen, würde sie existieren. Schauen wir uns mal an, wie man das macht:

-- Wir definieren zwei leere Tables
local testtable = {} 
local metatable = {} -- Unser Table für Metamethoden

-- Wir definieren eine Funktion für die 
-- Metamethode __index
metatable.__index = function(value, key)
  return "Nicht definiert"
end

-- Wir weisen unserem Table das Metatable zu
setmetatable(testtable, metatable)

testtable[3] = 42

print (testtable[1])
print (testtable[2])
print (testtable[3]) 

Wird das Skript nun ausgeführt erhalten wir statt nil die Ausgabe Nicht definiert. Und um zu demonstrieren, dass das nur greift, wenn ein Feld nicht definiert ist, habe ich noch einen Wert mit dem Index 3 definiert.

Aber das ist noch nicht alles. Wir können auch mit dem Index arbeiten. Ergänzen wir die Zeile wie folgt:

return key .. " ist nicht definiert"

Sehen wir in der Konsole direkt auf welchen, nicht vorhandenen Wert wir zugreifen wollten.

--[[
Alternativ kann man auch erst die Funktion definieren
und diese anschließend der entsprechenden Metamethode
zuweisen. Das ist vielleicht etwas übersichtlicher
oder einfacher zu verstehen, jedoch etwas mehr Schreibarbeit
--]]

function index(value, key)
  if key == 1 then
    return "eins"
  end
end

metatable.__index = index

setmetatable(testtable, metatable)

Ich würde nicht unbedingt empfehlen diese Methode produktiv einzusetzen, da man oft auf den Wert nil prüft um zu schauen, ob es einen Fehler gab. Ein sinnvolleres Beispiel wäre das folgende:

quadrat = { }
metatable = {}

metatable.__index = function(value, key)
  return key * key
end

setmetatable( quadrat, metatable )

print(quadrat[8])

Egal auf welchen Index wir hier zugreifen, wir würden immer die Quadratzahl zurückbekommen. Auch interesant ist die __call Methode. Mit der können wir unser Table wie eine Funktion verwenden:

local poly = { x = 10, y = 12, name = "Polytable" }
local meta = {}

meta.__call = function(self, var)
  return "Ich bin eigentlich ein Table! Und mein name ist " .. self.name
end
setmetatable(poly, meta)

print(poly("tag"))

Wie du siehst kann man so das Table wie eine Funktion aufrufen und auch Parameter übergeben. Über den ersten Parameter kann man auf das Table selbst zugreifen.

Anders funktioniert zum Beispiel die __tostring-Methode. Bestandteil der Lua-Standardbibliothek ist die tostring-Funktion. Sie konvertiert einen Wert in einen String. Also eine Zeichenkette, die man wie einen Text verarbeiten kann. Manchmal möchte man Werte in einer bestimmten Form als String erhalten. Die Besonderheit der tostring-Methode ist allerdings, dass man sie nicht via table.tostring() aufruft, sondern erst die Funktion tostring(table). Diese Funktion löst dann die Metamethode aus:

local poly = { x = 10, y = 12, name = "Polytable" }
local meta = {}
meta.__tostring = function(self, var)
  return self.y .. " auf der X-Achse und " .. self.y .. " auf der Y-Achse"
end

setmetatable(poly, meta)
print( tostring(poly) )

Ich hoffe, dass du nun eine Idee davon hast, was das Metatable ist und was Metamethoden sind und was man mit ihnen generell anstellen kann. Das Thema wurde jetzt hier nur oberflächlich behandelt. Es handelt sich aber auch nur um ein Grundlagentutorial. In einem weiterführenden Tutorial wird das Thema später noch ausführlicher behandelt. Fürs Erste braucht man das nicht unbedingt.

Tags: Lua weiterführende Themen

Letzte Bearbeitung:27.02.21 14:37 Uhr

 262

^ Nach oben

 Kommentare

Es wurden noch keine Kommentare geschrieben.