Introduzione alle metatabelle
Imposti e recuperi le metatabelle con setmetatable/getmetatable.
Introduzione alle metatabelle è una lezione Lua Academy gratuita su CoddyKit. Questa è la lezione 1 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.
Che cos'è una metatabella?
Una metatabella è una normale tabella Lua che controlla il comportamento di un'altra tabella. Quando Lua incontra un'operazione che non può eseguire su una tabella, come un'operazione aritmetica o l'accesso a una chiave mancante, cerca nella metatabella il metodo metametodo corrispondente. Questo è il meccanismo di estensione di Lua per l'overloading degli operatori e la programmazione orientata agli oggetti.
local t = {}
local mt = {__index = function(_, k) return "default_" .. k end}
setmetatable(t, mt)
print(t.foo) -- default_foo
print(t.bar) -- default_bar
print(t[1]) -- default_1setmetatable e getmetatable
setmetatable(t, mt) imposta mt come metatabella di t e restituisce t. getmetatable(t) restituisce la metatabella oppure nil se non è presente. Può impedire la modifica di una metatabella impostando mt.__metatable = "protected".
local t = {x = 10}
local mt = {}
setmetatable(t, mt)
print(getmetatable(t) == mt) -- true
-- Protect metatable
mt.__metatable = "locked"
print(getmetatable(t)) -- locked
-- setmetatable(t, {}) -- ERROR: cannot change protected metatable__index come tabella
Quando __index è una tabella, Lua cerca la chiave mancante in quella tabella. Questo costituisce la base dell'ereditarietà basata su prototipi di Lua. Se la chiave non è presente neanche in __index, Lua controlla la sua metatabella e prosegue nella catena.
local Animal = {sound = "...", legs = 4}
local Dog = setmetatable({sound = "Woof"}, {__index = Animal})
local Cat = setmetatable({sound = "Meow"}, {__index = Animal})
print(Dog.sound) -- Woof (own field)
print(Dog.legs) -- 4 (from Animal)
print(Cat.sound) -- Meow
print(Cat.legs) -- 4__index come funzione
Quando __index è una funzione, Lua la chiama passando la tabella e la chiave mancante. La funzione può calcolare o recuperare dinamicamente il valore. Restituisca nil da __index per indicare che la chiave non è stata trovata.
local dynamic = setmetatable({}, {
__index = function(t, k)
if k:sub(1,4) == "get_" then
local field = k:sub(5)
return function(self) return self[field] end
end
return nil
end
})
dynamic.name = "Lua"
local getter = dynamic.get_name
print(getter(dynamic)) -- Luarawget e rawset
rawget(t, k) legge una chiave della tabella senza attivare __index. rawset(t, k, v) imposta una chiave senza attivare __newindex. Utilizzi queste funzioni per ignorare i metametodi quando è necessario accedere direttamente alla tabella all'interno di un metametodo, evitando la ricorsione infinita.
local logged = setmetatable({}, {
__newindex = function(t, k, v)
print("Setting", k, "=", v)
rawset(t, k, v) -- bypass __newindex
end
})
logged.x = 10 -- Setting x = 10
logged.x = 20 -- no log! key now exists in t
print(logged.x) -- 20Più tabelle che condividono una metatabella
Una singola metatabella può essere condivisa da molte tabelle. È così che funzionano i sistemi di classi in Lua: tutte le istanze di una classe condividono la stessa metatabella, che contiene i metodi. Le modifiche alla metatabella influiscono su tutte le istanze.
local Mt = {
__index = {
greet = function(self)
print("Hello from " .. (self.name or "?"))
end
}
}
local a = setmetatable({name="Alice"}, Mt)
local b = setmetatable({name="Bob"}, Mt)
a:greet() -- Hello from Alice
b:greet() -- Hello from BobCampo __metatable
Impostare mt.__metatable su un valore qualsiasi fa sì che getmetatable restituisca quel valore invece della metatabella reale. In questo modo si impedisce agli utenti di ispezionare o sostituire la metatabella, una soluzione utile per l'incapsulamento e la sicurezza.
local secret = setmetatable({}, {
__metatable = false, -- hide metatable
__index = {value = 42}
})
print(secret.value) -- 42
print(getmetatable(secret)) -- false (not the real mt)
-- setmetatable(secret, {}) -- ERRORVerifica della metatabella
Usi getmetatable(t) per verificare se un oggetto ha una metatabella specifica (per il controllo del tipo). Poiché __metatable può nascondere la metatabella reale, usi rawequal o un campo indicatore per verifiche affidabili simili a isinstance.
local MyClass = {}
MyClass.__index = MyClass
MyClass.__metatable = MyClass -- use self as marker
function MyClass.new(x)
return setmetatable({x=x}, MyClass)
end
local obj = MyClass.new(5)
print(getmetatable(obj) == MyClass) -- true
print(obj.x) -- 5Metatabelle su valori non tabella
Le stringhe in Lua hanno già una metatabella (il modulo string). Per questo è possibile chiamare s:upper() su qualsiasi stringa. In Lua puro non è possibile impostare metatabelle sulle stringhe, sui numeri o sui booleani: solo sulle tabelle e sugli userdata.
local s = "hello"
local mt = getmetatable(s)
-- String metatable has __index = string library
print(mt.__index == string) -- true
-- So all string functions are methods:
print(s:upper()) -- HELLO
print(s:rep(3, "-")) -- hello-hello-helloDebug con le metatabelle
È possibile aggiungere un metametodo __tostring per controllare il modo in cui tostring() e print() visualizzano una tabella. È uno strumento prezioso per il debug di oggetti complessi.
local Point = {}
Point.__index = Point
Point.__tostring = function(p)
return string.format("Point(%g, %g)", p.x, p.y)
end
function Point.new(x, y)
return setmetatable({x=x,y=y}, Point)
end
local p = Point.new(3, 4)
print(tostring(p)) -- Point(3, 4)
print(p) -- Point(3, 4) (print calls tostring)Verifica rapida
Che cosa succede quando si accede a una chiave non trovata in una tabella che ha una metatabella con __index impostato su un'altra tabella?
Riepilogo: metatabelle
Riepilogo:
setmetatable(t, mt)/getmetatable(t)__index: tabella → ricerca nel prototipo; funzione → dispatch dinamicorawget/rawsetignorano i metametodi- Le metatabelle condivise consentono un comportamento simile a quello delle classi
__metatableprotegge la metatabella dall'ispezione__tostringcontrolla l'output di print
Domande Frequenti
La lezione «Introduzione alle metatabelle» è gratuita?
Sì — il testo completo di «Introduzione alle metatabelle» è 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 «Introduzione alle metatabelle»?
Imposti e recuperi le metatabelle con setmetatable/getmetatable. 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 1 di 4.
Quanto tempo richiede la lezione «Introduzione alle metatabelle»?
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