__index und __newindex
Fangen Sie das Lesen und Schreiben von Feldern mit den Metamethoden __index und __newindex ab
__index und __newindex ist eine kostenlose Lua Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Lua Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.
Zusammenfassung zu __index
__index wird ausgelöst, wenn Lua versucht, einen Schlüssel zu lesen, der in der Tabelle nicht vorhanden ist. Es kann sich dabei um eine Tabelle (Suche im Prototyp) oder eine Funktion (dynamische Berechnung) handeln. Dies ist die am häufigsten verwendete Metamethode in Lua – sie ermöglicht Vererbung, Standardwerte und verzögerte Initialisierung.
local defaults = {timeout=30, retries=3}
local config = setmetatable({timeout=60}, {__index=defaults})
print(config.timeout) -- 60 (own value)
print(config.retries) -- 3 (from defaults)
print(config.missing) -- nil (not in either)__newindex wird ausgelöst
__newindex wird ausgelöst, wenn Lua versucht, einen Schlüssel zu schreiben, der in der Tabelle noch nicht vorhanden ist. Wenn der Schlüssel bereits existiert, erfolgt die Zuweisung direkt, ohne __newindex auszulösen.
local proxy = setmetatable({}, {
__newindex = function(t, k, v)
print("New key:", k, "=", v)
rawset(t, k, v) -- actually store it
end
})
proxy.x = 10 -- New key: x = 10
proxy.x = 20 -- no trigger! x already exists
print(proxy.x) -- 20Schreibgeschützte Tabellen
Verwenden Sie __newindex, um schreibgeschützte Tabellen zu erstellen. Fangen Sie alle Schreibzugriffe ab und lösen Sie einen Fehler aus. Kombinieren Sie dies mit __index, um Werte bereitzustellen, ohne sie in der Tabelle selbst zu speichern.
local function readOnly(t)
return setmetatable({}, {
__index = t,
__newindex = function(_, k, _)
error("attempt to write to read-only table key: " .. tostring(k), 2)
end
})
end
local cfg = readOnly({host="localhost", port=8080})
print(cfg.host) -- localhost
-- cfg.host = "x" -- ERROR: attempt to write to read-only tableÄnderungen nachverfolgen
Verwenden Sie __newindex, um alle Änderungen an einer Tabelle nachzuverfolgen – nützlich für Debugging, Änderungsprotokolle oder reaktive Datenbindungen. Speichern Sie die Daten in einer verborgenen „Backing“-Tabelle und protokollieren Sie die Änderungen.
local log = {}
local data = {}
local tracked = setmetatable({}, {
__index = data,
__newindex = function(_, k, v)
log[#log+1] = {key=k, old=data[k], new=v}
data[k] = v
end
})
tracked.name = "Alice"
tracked.age = 30
tracked.name = "Bob"
for _, entry in ipairs(log) do
print(entry.key, entry.old, "->", entry.new)
endProxy-Objekte
Ein Proxy umschließt ein anderes Objekt, um alle Lese- und Schreibzugriffe abzufangen. Verwenden Sie eine leere Tabelle als Proxy, bei der sowohl __index als auch __newindex auf Funktionen verweisen. Die tatsächlichen Daten befinden sich in einer separaten Tabelle.
local function makeProxy(target)
return setmetatable({}, {
__index = function(_, k) return target[k] end,
__newindex = function(_, k, v)
print("Setting", k, "on target")
target[k] = v
end,
})
end
local real = {x=10}
local p = makeProxy(real)
print(p.x) -- 10 (reads from real)
p.y = 20 -- Setting y on target
print(real.y) -- 20__index-Kette (Vererbung)
Durch das Verketten von __index-Metatabellen entsteht eine prototypbasierte Vererbung. Wenn ein Schlüssel im Objekt nicht gefunden wird, prüft Lua die Klasse, dann die übergeordnete Klasse und so weiter. Jede Ebene benötigt eine eigene Metatabelle, deren __index auf die nächste Ebene verweist.
local Base = {type = "base", version = 1}
local Child = setmetatable({type = "child"}, {__index = Base})
local Obj = setmetatable({}, {__index = Child})
print(Obj.type) -- base? No: child (Child has it)
print(Obj.version) -- 1 (from Base)
print(Obj.type) -- child (Child overrides Base.type)Verzögerte Initialisierung mit __index
Verwenden Sie ein __index in Funktionsform, um aufwendige Werte beim ersten Zugriff zu berechnen und zwischenzuspeichern. Beim ersten Lesen berechnen Sie den Wert und speichern ihn direkt in der Tabelle (dadurch werden spätere Aufrufe von __index umgangen).
local lazy = setmetatable({}, {
__index = function(t, k)
if k == "expensiveData" then
print("Computing...")
local result = {1,2,3,4,5} -- simulate work
rawset(t, k, result)
return result
end
end
})
print(lazy.expensiveData) -- Computing... then table
print(lazy.expensiveData) -- (no "Computing" this time)__newindex zur Schemavalidierung
Verwenden Sie __newindex, um ein Schema durchzusetzen: Erlauben Sie nur das Setzen vordefinierter Schlüssel oder von Werten des richtigen Typs. Dadurch erhalten Lua-Tabellen eine einfache Typsicherheit.
local schema = {name="string", age="number", active="boolean"}
local function schemaTable()
local store = {}
return setmetatable({}, {
__index = store,
__newindex = function(_, k, v)
local expected = schema[k]
if not expected then error("unknown key: "..k,2) end
if type(v) ~= expected then
error(k.." must be "..expected..", got "..type(v),2)
end
store[k] = v
end
})
end
local user = schemaTable()
user.name = "Alice"
user.age = 30
-- user.age = "thirty" -- ERROR__index vs. rawget
Verwenden Sie innerhalb einer __index-Funktion rawget, um aus der Tabelle zu lesen, ohne __index erneut auszulösen (was zu einer Endlosrekursion führen würde). Verwenden Sie innerhalb von Metamethoden immer rawget/rawset, um den tatsächlichen Tabellenspeicher zu bearbeiten.
local counter = setmetatable({count=0}, {
__index = function(t, k)
-- Use rawget to avoid recursion
local c = rawget(t, "count")
rawset(t, "count", c + 1)
return rawget(t, k)
end
})
print(counter.count) -- 0 (direct, no __index)
print(counter.missing) -- nil
print(counter.count) -- 1 (incremented)__index und __newindex kombinieren
Das leistungsfähigste Muster: Verwenden Sie eine leere Proxy-Tabelle mit __index und __newindex, die von einer verborgenen Datentabelle unterstützt wird. Dadurch erhalten Sie vollständige Kontrolle über Lese- und Schreibzugriffe und können Funktionen wie Änderungserkennung, verzögertes Laden und Zugriffskontrolle umsetzen.
local function observable(init)
local data = init or {}
local listeners = {}
local obj = setmetatable({}, {
__index = data,
__newindex = function(_, k, v)
local old = data[k]
data[k] = v
for _, cb in ipairs(listeners) do cb(k,old,v) end
end
})
obj._onchange = function(_, cb) listeners[#listeners+1]=cb end
return obj
end
local obs = observable({score=0})
obs:_onchange(function(k,o,n) print(k,o,"->",n) end)
obs.score = 100 -- score 0 -> 100Schnelltest
Wann wird __newindex NICHT ausgelöst?
Zusammenfassung: __index und __newindex
Wichtige Punkte:
__index: wird beim Lesen eines fehlenden Schlüssels ausgelöst; Tabelle oder Funktion__newindex: wird nur beim Schreiben eines neuen Schlüssels ausgelöst- Verwenden Sie innerhalb von Metamethoden
rawget/rawset, um Rekursion zu vermeiden - Muster: schreibgeschützte Tabellen, Änderungsnachverfolgung, verzögerte Initialisierung, Schemavalidierung
- Leerer Proxy + Backing-Tabelle = vollständiges Abfangen von Lese- und Schreibzugriffen
Häufig gestellte Fragen
Ist die Lektion „__index und __newindex“ kostenlos?
Ja — der vollständige Text von „__index und __newindex“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Lua Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „__index und __newindex“?
Fangen Sie das Lesen und Schreiben von Feldern mit den Metamethoden __index und __newindex ab Du übst Lua Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Lua Academy zu starten?
Keine Vorkenntnisse erforderlich. Lua Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „__index und __newindex“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Lua Academy-Lektion Code schreiben und ausführen?
Ja. Jede Lua Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Einführung in Metatabellen
- __index und __newindex
- Arithmetische Metamethoden
- __tostring und __len