__index og __newindex
Opfang læsning og skrivning af felter med metametoderne __index og __newindex.
__index og __newindex er en gratis Lua Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Lua Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Lua Academy-kurset indeholder 4 lektioner i alt.
Opsummering af __index
__index udløses, når Lua forsøger at læse en nøgle, der ikke findes i tabellen. Det kan være en tabel (opslag i prototype) eller en funktion (dynamisk beregning). Dette er den mest anvendte metametode i Lua – den understøtter nedarvning, standardværdier og doven initialisering.
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 udløses
__newindex udløses, når Lua forsøger at skrive en nøgle, der endnu ikke findes i tabellen. Hvis nøglen allerede findes, sker tildelingen direkte uden at udløse __newindex.
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) -- 20Skrivebeskyttede tabeller
Brug __newindex til at oprette skrivebeskyttede tabeller. Opfang alle skrivehandlinger, og udløs en fejl. Kombiner det med __index for at levere værdier uden at gemme dem i selve tabellen.
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 tableSporing af ændringer
Brug __newindex til at spore alle ændringer i en tabel – det er nyttigt til fejlfinding, ændringslogning eller reaktive databindinger. Gem data i en skjult tabel, og registrer ændringer i en log.
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-objekter
En proxy omslutter et andet objekt for at opfange alle læsninger og skrivninger. Brug en tom tabel som proxy, hvor både __index og __newindex peger på funktioner. De rigtige data ligger i en separat tabel.
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-kæde (nedarvning)
Ved at kæde __index-metatabeller sammen opretter du prototypenedarvning. Når en nøgle ikke findes i objektet, kontrollerer Lua klassen, derefter forældreklassen og så videre. Hvert niveau skal have sin egen metatabel med __index, der peger på det næste niveau.
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)Doven initialisering med __index
Brug en funktionsform af __index til at beregne og cache dyre værdier ved første adgang. Ved den første læsning beregnes værdien og gemmes direkte i tabellen, så fremtidige kald af __index omgås.
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 til skemavalidering
Brug __newindex til at håndhæve et skema: Tillad kun angivelse af foruddefinerede nøgler eller værdier af den korrekte type. Det giver letvægtstypekontrol i Lua-tabeller.
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 kontra rawget
Brug rawget inde i en __index-funktion til at læse fra tabellen uden at udløse __index igen, hvilket ellers ville medføre uendelig rekursion. Brug altid rawget/rawset inde i metametoder til at manipulere den faktiske lagerplads i tabellen.
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)Kombination af __index og __newindex
Det mest kraftfulde mønster er at bruge en tom proxy-tabel med både __index og __newindex, understøttet af en skjult datatabel. Det giver fuld kontrol over læsninger og skrivninger og muliggør funktioner som ændringsregistrering, doven indlæsning og adgangskontrol.
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 -> 100Hurtigt tjek
Hvornår udløses __newindex IKKE?
Opsummering: __index og __newindex
Vigtige punkter:
__index: udløses ved læsning af en manglende nøgle; tabel eller funktion__newindex: udløses kun ved skrivning af en ny nøgle- Brug
rawget/rawsetinde i metametoder for at undgå rekursion - Mønstre: skrivebeskyttede tabeller, ændringssporing, doven initialisering, skemavalidering
- Tom proxy + understøttende tabel = fuld opfangning af læsninger og skrivninger
Lær Lua med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 40
- Lektioner
- 159
Ofte stillede spørgsmål
Er lektionen “__index og __newindex” gratis?
Ja — alle 3 lektioner i læringssporet Lua Academy, inklusive “__index og __newindex”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Lua Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “__index og __newindex”?
Opfang læsning og skrivning af felter med metametoderne __index og __newindex. Du øver dig i Lua Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Lua Academy?
Der kræves ingen tidligere erfaring. Lua Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “__index og __newindex”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Lua Academy-lektion?
Ja. Alle Lua Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Introduktion til metatabeller
- __index og __newindex
- Aritmetiske metametoder
- __tostring og __len