Menu
CoddyTech

Die __newindex-Metamethode

Teil des Abschnitts Logik und Programmablauf der Lua-Journey von Coddy. Lektion 19 von 54.

Du hast gelernt, wie __index steuert, was passiert, wenn du versuchst, einen Schlüssel auszulesen, der in einer Tabelle nicht existiert. Jetzt lernst du sein Gegenstück kennen: __newindex, das steuert, was passiert, wenn du einem Schlüssel einen Wert zuweist, den die Tabelle noch nicht hat.

Die Metamethode __newindex wird ausgelöst, wenn du versuchst, einem Schlüssel, der derzeit nicht in der Tabelle vorhanden ist, einen Wert zuzuweisen. Dadurch kannst du Änderungen abfangen und kontrollieren, bevor sie vorgenommen werden.

Hier ist ein einfaches Beispiel, das verhindert, dass einer Tabelle neue Schlüssel 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: nil

Wenn du versuchst, readOnly.name = "Alice" zu setzen, sieht Lua, dass name in der Tabelle nicht existiert. Anstatt es hinzuzufügen, ruft Lua die Funktion __newindex mit drei Argumenten auf: der Tabelle selbst, dem Schlüssel, der festgelegt wird, und dem zugewiesenen Wert.

In diesem Beispiel gibt die Funktion einfach eine Nachricht aus und speichert tatsächlich nichts.

Du kannst auch __newindex verwenden, um Daten zu validieren, bevor du sie in deine Tabelle übernimmst:

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     -- Erlaubt, mit rawset gespeichert
player.health = "high"  -- Keine Meldung: health existiert jetzt

Beachte die Verwendung von rawset() im zweiten Beispiel. Diese Funktion umgeht die Metatabelle und setzt den Wert direkt in der Tabelle.

Ohne sie würde das Setzen des Werts erneut __newindex auslösen und eine Endlosschleife erzeugen.

Da __newindex nur für Schlüssel ausgeführt wird, die die Tabelle noch nicht enthält, schützt diese Prüfung die erste Zuweisung jedes Schlüssels. Sobald rawset health gespeichert hat, ändern spätere Zuweisungen den Wert direkt. Um jede Zuweisung zu prüfen, lass die Tabelle selbst leer und speichere die Werte in einer zweiten Tabelle, auf die sie über __index zugreift:

local data = {}
local player = setmetatable({}, {
    __index = data,
    __newindex = function(t, key, value)
        if key == "health" and type(value) ~= "number" then
            print("Health must be a number!")
        else
            data[key] = value
        end
    end
})

player.health = 100
player.health = "high"  -- Ausgabe: Health must be a number!
print(player.health)    -- Ausgabe: 100

player erhält nie einen eigenen Schlüssel, daher läuft jede Zuweisung über __newindex, und jeder Lesezugriff fällt über __index auf data zurück.

challenge icon

Aufgabe

Einfach

Schreibe eine Funktion createValidatedTable, die key und value entgegennimmt und eine Tabelle zurückgibt, die für neue Schlüssel nur Zeichenfolgenwerte akzeptiert.

Erstelle eine leere Tabelle und verknüpfe sie mit einer Metatabelle mit __newindex, die den Werttyp überprüft. Wenn jemand versucht, einen Wert hinzuzufügen, der keine Zeichenfolge ist, verwende rawset(), um stattdessen die Zeichenfolge "invalid" zu speichern. Speichere Zeichenfolgenwerte normal mit rawset().

Logik:

  • Erstelle eine leere Tabelle
  • Erstelle eine Metatabelle mit __newindex, die die Tabelle, den Schlüssel und den Wert entgegennimmt
  • Prüfe innerhalb von __newindex mit type(value) == "string", ob der Wert eine Zeichenfolge ist
  • Verwende bei einer Zeichenfolge rawset(t, key, value), um sie zu speichern
  • Ist der Wert keine Zeichenfolge, verwende rawset(t, key, "invalid"), um stattdessen "invalid" zu speichern
  • Verknüpfe die Metatabelle mithilfe von setmetatable() mit der Tabelle
  • Verwende rawset(), um das anfängliche Schlüssel-Wert-Paar zur Tabelle hinzuzufügen (und dabei die Metatabelle zu umgehen)
  • Gib die Tabelle zurück

Parameter:

  • key (Zeichenfolge): Der anfängliche Schlüssel, der der Tabelle hinzugefügt werden soll
  • value (Zeichenfolge): Der anfängliche Wert, der der Tabelle hinzugefügt werden soll

Rückgabe: Eine Tabelle mit Validierung, die nur Zeichenfolgenwerte akzeptiert und das anfängliche Schlüssel-Wert-Paar enthält (Tabelle)

Probier es selbst

function createValidatedTable(key, value)
    -- Schreibe hier den Code
end
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Logik und Programmablauf

Übe selbstständig: Online-Lua-Compiler