__index e __newindex
Intercetti la lettura e la scrittura dei campi con i metametodi __index e __newindex.
__index e __newindex è una lezione Lua Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Lua Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Lua Academy include 4 lezioni in totale.
Riepilogo di __index
__index viene attivato quando Lua prova a leggere una chiave che non esiste nella tabella. Può essere una tabella (ricerca nel prototipo) oppure una funzione (calcolo dinamico). È il metametodo più usato in Lua: abilita l'ereditarietà, i valori predefiniti e l'inizializzazione differita.
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)Attivazione di __newindex
__newindex viene attivato quando Lua prova a scrivere una chiave che non esiste ancora nella tabella. Se la chiave esiste già, l'assegnazione avviene direttamente senza attivare __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) -- 20Tabelle di sola lettura
Usi __newindex per creare tabelle di sola lettura. Intercetti tutte le scritture e generi un errore. Combini questo metametodo con __index per fornire valori senza memorizzarli direttamente nella tabella.
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 tableMonitoraggio delle modifiche
Usi __newindex per monitorare tutte le modifiche a una tabella, una soluzione utile per il debug, la registrazione delle modifiche o i binding reattivi dei dati. Memorizzi i dati in una tabella di supporto nascosta e registri le modifiche in un 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)
endOggetti proxy
Un proxy avvolge un altro oggetto per intercettare tutte le letture e le scritture. Usi una tabella vuota come proxy, con __index e __newindex che puntano entrambi a funzioni. I dati reali risiedono in una tabella separata.
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) -- 20Catena di __index (ereditarietà)
Collegare metatabelle tramite __index crea un'ereditarietà basata sui prototipi. Quando una chiave non viene trovata nell'oggetto, Lua controlla la classe, poi la classe padre e così via. Ogni livello richiede una propria metatabella con __index che punta al livello successivo.
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)Inizializzazione differita con __index
Usi un __index in forma di funzione per calcolare e memorizzare nella cache i valori costosi al primo accesso. Alla prima lettura, calcoli il valore e lo memorizzi direttamente nella tabella, evitando le successive invocazioni di __index.
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 per la validazione dello schema
Usi __newindex per applicare uno schema: consenti solo l'impostazione di chiavi predefinite o di valori del tipo corretto. In questo modo aggiungi alle tabelle Lua una sicurezza sui tipi di base.
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 e rawget a confronto
All'interno di una funzione __index, usi rawget per leggere dalla tabella senza attivare nuovamente __index, cosa che causerebbe una ricorsione infinita. All'interno dei metametodi, usi sempre rawget/rawset per manipolare l'archiviazione effettiva della tabella.
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)Combinare __index e __newindex
Il pattern più potente consiste nell'usare una tabella proxy vuota con __index e __newindex, supportata da una tabella di dati nascosta. In questo modo si ottiene il pieno controllo sulle letture e sulle scritture, abilitando funzionalità come il rilevamento delle modifiche, il caricamento differito e il controllo degli accessi.
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 -> 100Verifica rapida
Quando NON viene attivato __newindex?
Riepilogo: __index e __newindex
Punti chiave:
__index: si attiva quando si legge una chiave mancante; può essere una tabella o una funzione__newindex: si attiva solo quando si scrive una nuova chiave- Usi
rawget/rawsetall'interno dei metametodi per evitare la ricorsione - Pattern: tabelle di sola lettura, monitoraggio delle modifiche, inizializzazione differita, validazione dello schema
- Proxy vuoto + tabella di supporto = intercettazione completa delle letture e delle scritture
Impara Lua con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 40
- Lezioni
- 159
Domande Frequenti
La lezione «__index e __newindex» è gratuita?
Sì — il testo completo di «__index e __newindex» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Lua Academy, passa a CoddyKit PRO. Il corso Lua Academy include 4 lezioni in totale.
Cosa imparerò in «__index e __newindex»?
Intercetti la lettura e la scrittura dei campi con i metametodi __index e __newindex. Eserciti Lua Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Lua Academy?
Non è richiesta alcuna esperienza precedente. Lua Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «__index e __newindex»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Lua Academy?
Sì. Ogni lezione Lua Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Introduzione alle metatabelle
- __index e __newindex
- Metametodi aritmetici
- __tostring e __len