0Pricing
Lua Academy · Lektion

__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)  -- 20

Schreibgeschü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)
end

Proxy-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 Änderungs­erkennung, 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 -> 100

Schnelltest

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

  1. Einführung in Metatabellen
  2. __index und __newindex
  3. Arithmetische Metamethoden
  4. __tostring und __len
← Zurück zu Lua Academy