Die __newindex-Metamethode
Teil des Abschnitts Logic & Flow der Lua-Journey von Coddy — Lektion 19 von 54.
Sie haben gelernt, wie __index steuert, was passiert, wenn Sie versuchen, einen Schlüssel zu lesen, der in einer Tabelle nicht existiert. Jetzt werden Sie sein Gegenstück entdecken: __newindex, das steuert, was passiert, wenn Sie versuchen, ein Schlüssel-Wert-Paar hinzuzufügen oder zu ändern.
Die __newindex-Metamethode wird immer dann ausgelöst, wenn Sie versuchen, einem Schlüssel einen Wert zuzuweisen, der derzeit nicht in der Tabelle existiert. Dies gibt Ihnen die Möglichkeit, Änderungen abzufangen und zu steuern, bevor sie stattfinden.
Hier ist ein einfaches Beispiel, das verhindert, dass neue Schlüssel zu einer Tabelle hinzugefügt werden:
local readOnly = {}
local meta = {
__newindex = function(table, key, value)
print("Cannot add key: " .. key)
end
}
setmetatable(readOnly, meta)
readOnly.name = "Alice" -- Ausgabe: Cannot add key: name
print(readOnly.name) -- Ausgabe: nilWenn Sie versuchen, readOnly.name = "Alice" zu setzen, sieht Lua, dass name in der Tabelle nicht existiert. Anstatt es hinzuzufügen, ruft Lua die __newindex-Funktion mit drei Argumenten auf: die Tabelle selbst, der zu setzende Schlüssel und der zugewiesene Wert.
In diesem Beispiel gibt die Funktion einfach eine Nachricht aus und speichert eigentlich nichts.
Du kannst auch __newindex verwenden, um Daten zu validieren, bevor sie in deine Tabelle aufgenommen werden:
local player = {}
local meta = {
__newindex = function(t, key, value)
if key == "health" and type(value) ~= "number" then
print("Health must be a number!")
else
rawset(t, key, value)
end
end
}
setmetatable(player, meta)
player.health = "high" -- Ausgabe: Health must be a number!
player.health = 100 -- ErlaubtBeachten Sie die Verwendung von rawset() im zweiten Beispiel. Diese Funktion umgeht die Metatabelle und setzt den Wert direkt in der Tabelle.
Ohne dies würde das Setzen des Wertes __newindex erneut auslösen und so eine Endlosschleife erzeugen.
Aufgabe
EinfachSchreiben Sie eine Funktion createValidatedTable, die key und value entgegennimmt und eine Tabelle zurückgibt, die nur String-Werte für neue Schlüssel akzeptiert.
Erstellen Sie eine leere Tabelle und fügen Sie eine Metatabelle mit __newindex hinzu, die den Werttyp validiert. Wenn jemand versucht, einen Nicht-String-Wert hinzuzufügen, verwenden Sie rawset(), um stattdessen den String "invalid" zu speichern. Für String-Werte speichern Sie diese normal mit rawset().
Logik:
- Erstellen Sie eine leere Tabelle
- Erstellen Sie eine Metatabelle mit
__newindex, die die Tabelle, den Schlüssel und den Wert empfängt - Überprüfen Sie innerhalb von
__newindexmittype(value) == "string", ob der Wert ein String ist - Wenn es ein String ist, verwenden Sie
rawset(t, key, value), um ihn zu speichern - Wenn es kein String ist, verwenden Sie
rawset(t, key, "invalid"), um stattdessen"invalid"zu speichern - Verknüpfen Sie die Metatabelle mit der Tabelle unter Verwendung von
setmetatable() - Verwenden Sie
rawset(), um das initiale Schlüssel-Wert-Paar zur Tabelle hinzuzufügen (unter Umgehung der Metatabelle) - Geben Sie die Tabelle zurück
Parameter:
key(string): Der initiale Schlüssel, der der Tabelle hinzugefügt werden sollvalue(string): Der initiale Wert, der der Tabelle hinzugefügt werden soll
Rückgabewert: Eine Tabelle mit Validierung, die nur String-Werte akzeptiert und das initiale Schlüssel-Wert-Paar enthält (table)
Spickzettel
Die Metamethode __newindex wird ausgelöst, wenn Sie versuchen, einem Schlüssel, der in einer Tabelle nicht existiert, einen Wert zuzuweisen, was es Ihnen ermöglicht, Änderungen abzufangen und zu steuern.
Einfaches Beispiel, das neue Schlüssel verhindert:
local readOnly = {}
local meta = {
__newindex = function(table, key, value)
print("Cannot add key: " .. key)
end
}
setmetatable(readOnly, meta)
readOnly.name = "Alice" -- Ausgabe: Cannot add key: name
print(readOnly.name) -- Ausgabe: nilDie Funktion __newindex erhält drei Argumente: die Tabelle selbst, den Schlüssel, der gesetzt wird, und den Wert, der zugewiesen wird.
Validierung von Daten mit __newindex:
local player = {}
local meta = {
__newindex = function(t, key, value)
if key == "health" and type(value) ~= "number" then
print("Health must be a number!")
else
rawset(t, key, value)
end
end
}
setmetatable(player, meta)
player.health = "high" -- Ausgabe: Health must be a number!
player.health = 100 -- ErlaubtVerwenden Sie rawset(t, key, value), um die Metatabelle zu umgehen und Werte direkt in der Tabelle zu setzen. Dies verhindert Endlosschleifen beim Setzen von Werten innerhalb von __newindex.
Probier es selbst
function createValidatedTable(key, value)
-- Code hier schreiben
end
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Logic & Flow
1Fortgeschrittene Table-Iteration
Iterieren mit pairs()Iterieren mit ipairs()pairs() vs. ipairs()Zusammenfassung – Charakterbogen4Einführung in Metatables
Was ist eine Metatable?setmetatable & getmetatableDie __index-MetamethodeDie __newindex-MetamethodeDie __tostring-MetamethodeArithmetische Metamethoden Teil 1Arithmetische Metamethoden Teil 2Zusammenfassung – Schreibgeschützte Tabellen7Fortgeschrittene String-Manipulation
string.gsub() für ErsetzungenEinführung in String-Patternsstring.find()string.match()Iterieren mit string.gmatch()Rückblick – Log-File-Parser2Weitere Funktionen der Table-Bibliothek
table.concat()Tabellenerstellung & unpack()table.sort()Benutzerdefiniertes Sortieren mit FunktionenRückblick – Highscore-Tabelle