Lua-Metatabelle

In einer Lua-Tabelle können wir über den entsprechenden Schlüssel auf den Wert zugreifen, aber wir können keine Operationen auf zwei Tabellen ausführen (wie z. B. Addition).

Daher stellt Lua Metatabellen bereit, mit denen wir das Verhalten von Tabellen ändern können. Jedes Verhalten ist einer entsprechenden Metamethode zugeordnet.

Zum Beispiel können wir mithilfe von Metatabellen definieren, wie Lua die Additionsoperation a+b zweier Tabellen berechnet.

Wenn Lua versucht, zwei Tabellen zu addieren, prüft es zuerst, ob eine von ihnen eine Metatabelle hat, und prüft dann, ob es ein Feld namens__addgibt. Wenn es gefunden wird, wird der entsprechende Wert aufgerufen.__addFelder wie diese; ihre entsprechenden Werte (oft eine Funktion oder eine Tabelle) sind die "Metamethoden".

Es gibt zwei sehr wichtige Funktionen zur Behandlung von Metatabellen:

  • setmetatable(table,metatable):Legt die Metatabelle für die angegebene Tabelle fest. Wenn die Metatabelle einen __metatable-Schlüssel enthält, schlägt setmetatable fehl.
  • getmetatable(table):Gibt die Metatabelle des Objekts zurück.

Das folgende Beispiel zeigt, wie man eine Metatabelle für eine angegebene Tabelle festlegt:

mytable = {}                          -- gewöhnliche Tabelle
mymetatable = {}                      -- Metatabelle
setmetatable(mytable,mymetatable)     -- setzt mymetatable als die Metatabelle von mytable

Der obige Code kann auch in einer Zeile geschrieben werden:

mytable = setmetatable({},{})

Das Folgende gibt die Metatabelle eines Objekts zurück:

getmetatable(mytable)                 -- 这会返回 mymetatable

__index-Metamethode

Dies ist der am häufigsten verwendete Schlüssel in einer Metatabelle.

Wenn Sie über einen Schlüssel auf eine Tabelle zugreifen und der Schlüssel keinen Wert hat, sucht Lua nach dem Schlüssel __index in der Metatabelle der Tabelle (vorausgesetzt, es gibt eine Metatabelle). Wenn __index eine Tabelle enthält, sucht Lua den entsprechenden Schlüssel in dieser Tabelle.

Wir können den Befehl lua verwenden, um in den interaktiven Modus zu wechseln und zu prüfen:

$ lua
Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
> other = { foo = 3 }
> t = setmetatable({}, { __index = other })
> t.foo
3
> t.bar
nil

Wenn __index eine Funktion enthält, ruft Lua diese Funktion auf und übergibt die Tabelle und den Schlüssel als Argumente an die Funktion.

Die __index-Metamethode prüft, ob ein Element in der Tabelle vorhanden ist. Wenn es nicht vorhanden ist, ist das zurückgegebene Ergebnis nil; wenn es vorhanden ist, wird das Ergebnis von __index zurückgegeben.

Beispiel

mytable = setmetatable({key1 = "value1"}, {
  __index = function(mytable, key)
    if key == "key2" then
      return "metatablevalue"
    else
      return nil
    end
  end
})

print(mytable.key1,mytable.key2)

Die Ausgabe des Beispiels ist:

value1    metatablevalue

Beispielanalyse:

  • Die Tabelle mytable wird zugewiesen als{key1 = "value1"}。

  • Für mytable ist eine Metatabelle gesetzt, und die Metamethode ist __index.

  • Suche nach key1 in der Tabelle mytable. Wenn gefunden, gib das Element zurück; wenn nicht gefunden, fahre fort.

  • Suche nach key2 in der Tabelle mytable. Wenn gefunden, gib metatablevalue zurück; wenn nicht gefunden, fahre fort.

  • Stelle fest, ob die Metatabelle eine __index-Methode hat. Wenn die __index-Methode eine Funktion ist, rufe diese Funktion auf.

  • Prüfe in der Metamethode, ob der Schlüsselparameter "key2" übergeben wird (mytable.key2 ist gesetzt). Wenn der Parameter "key2" übergeben wird, gib "metatablevalue" zurück; andernfalls gib den entsprechenden Wert von mytable für den Schlüssel zurück.

Wir können den obigen Code einfach umschreiben als:

mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)

Zusammenfassung

Die Regeln, wenn Lua ein Tabellenelement nachschlägt, sind tatsächlich die folgenden 3 Schritte:

  • 1. Suche in der Tabelle. Wenn gefunden, gib das Element zurück; wenn nicht gefunden, fahre fort.
  • 2. Stelle fest, ob die Tabelle eine Metatabelle hat. Wenn sie keine Metatabelle hat, gib nil zurück; wenn sie eine Metatabelle hat, fahre fort.
  • 3. Stelle fest, ob die Metatabelle eine __index-Methode hat. Wenn die __index-Methode nil ist, gib nil zurück; wenn die __index-Methode eine Tabelle ist, wiederhole die Schritte 1, 2 und 3; wenn die __index-Methode eine Funktion ist, gib den Rückgabewert dieser Funktion zurück.

Dieser Teil stammt von Autor Huanzi: https://blog.csdn.net/xocoder/article/details/9028347


__newindex-Metamethode

Die __newindex-Metamethode wird zum Aktualisieren von Tabellen verwendet, während __index für den Zugriff auf Tabellen verwendet wird.

Wenn Sie einem fehlenden Index einer Tabelle einen Wert zuweisen, sucht der Interpreter nach der __newindex-Metamethode: Wenn sie existiert, ruft er diese Funktion auf, ohne die Zuweisung durchzuführen.

Das folgende Beispiel veranschaulicht die Anwendung der __newindex-Metamethode:

Beispiel

mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "new value 2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "new value 1"
print(mytable.key1,mymetatable.key1)

Die Ausgabe nach Ausführung des obigen Beispiels ist:

value1
nil    新值2
新值1    nil

Im obigen Beispiel ist die Metamethode __newindex für die Tabelle gesetzt. Wenn einem neuen Indexschlüssel (newkey) ein Wert zugewiesen wird (mytable.newkey = "new value 2"), wird die Metamethode aufgerufen und die Zuweisung wird nicht ausgeführt. Wenn einem vorhandenen Indexschlüssel (key1) ein Wert zugewiesen wird, wird die Zuweisung ausgeführt und die __newindex-Metamethode wird nicht aufgerufen.

Das folgende Beispiel verwendet die rawset-Funktion, um eine Tabelle zu aktualisieren:

Beispiel

mytable = setmetatable({key1 = "value1"}, {
    __newindex = function(mytable, key, value)
        rawset(mytable, key, "\""..value.."\"")
    end
})

mytable.key1 = "new value"
mytable.key2 = 4

print(mytable.key1,mytable.key2)

Die Ausgabe nach Ausführung des obigen Beispiels ist:

new value    "4"

Hinzufügen von Operatoren zu Tabellen

Das folgende Beispiel demonstriert die Addition zweier Tabellen:

Beispiel

-- Benutzerdefinierte Funktion table_maxn zur Berechnung des maximalen Schlüsselwerts in einer Tabelle, d. h. Rückgabe des maximalen Schlüsselwerts der Tabelle
function table_maxn(t)
    local mn = 0
    for k, _ in pairs(t) do
        if type(k) == "number" and k > mn then
            mn = k
        end
    end
    return mn
end

-- Additionsoperation von zwei Tabellen
mytable = setmetatable({ 1, 2, 3 }, {
  __add = function(mytable, newtable)
    local max_key_mytable = table_maxn(mytable)
    for i = 1, table_maxn(newtable) do
      table.insert(mytable, max_key_mytable + i, newtable[i])
    end
    return mytable
  end
})

secondtable = {4, 5, 6}

mytable = mytable + secondtable

for k, v in ipairs(mytable) do
    print(k, v)
end

Die Ausgabe nach Ausführung des obigen Beispiels ist:

1    1
2    2
3    3
4    4
5    5
6    6

Der Schlüssel __add ist in der Metatabelle enthalten und führt die Additionsoperation aus. Die Liste der entsprechenden Operationen in der Tabelle lautet wie folgt: (Hinweis:__sind zwei Unterstriche)

MusterBeschreibung
__addEntsprechender Operator '+'.
__subEntsprechender Operator '-'.
__mulEntsprechender Operator '*'.
__divEntsprechender Operator '/'.
__modEntsprechender Operator '%'.
__unmEntsprechender Operator '-'.
__concatEntsprechender Operator '..'.
__eqEntsprechender Operator '=='.
__ltEntsprechender Operator '<'.
__leEntsprechender Operator '<='.

__call-Metamethode

Die __call-Metamethode wird aufgerufen, wenn Lua einen Wert aufruft. Das folgende Beispiel demonstriert die Berechnung der Summe der Elemente in einer Tabelle:

Beispiel

-- Berechne den maximalen Wert in der Tabelle; table.maxn kann in Lua-Versionen über 5.2 nicht verwendet werden
-- Benutzerdefinierte Funktion table_maxn zur Berechnung des maximalen Schlüsselwerts in einer Tabelle, d. h. zur Berechnung der Anzahl der Elemente in der Tabelle
function table_maxn(t)
    local mn = 0
    for k, v in pairs(t) do
        if mn < k then
            mn = k
        end
    end
    return mn
end

-- Definiere die Metamethode __call
mytable = setmetatable({10}, {
  __call = function(mytable, newtable)
        sum = 0
        for i = 1, table_maxn(mytable) do
                sum = sum + mytable[i]
        end
    for i = 1, table_maxn(newtable) do
                sum = sum + newtable[i]
        end
        return sum
  end
})
newtable = {10,20,30}
print(mytable(newtable))

Die Ausgabe nach Ausführung des obigen Beispiels ist:

70

__tostring-Metamethode

Die __tostring-Metamethode wird verwendet, um das Ausgabeverhalten einer Tabelle zu ändern. Im folgenden Beispiel passen wir den Ausgabeinhalt einer Tabelle an:

Beispiel

mytable = setmetatable({ 10, 20, 30 }, {
  __tostring = function(mytable)
    sum = 0
    for k, v in p(mytable) do
                sum = sum + v
        end
    return "Die Summe aller Elemente in der Tabelle ist " .. sum
  end
})
print(mytable)

Die Ausgabe nach Ausführung des obigen Beispiels ist:

表所有元素的和为 60

Daraus

Weitere Erweiterungen