0Pricing
Lua Academy · Lezione

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_1

setmetatable 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))   -- Lua

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

Più 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 Bob

Campo __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, {}) -- ERROR

Verifica 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)                           -- 5

Metatabelle 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-hello

Debug 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 dinamico
  • rawget/rawset ignorano i metametodi
  • Le metatabelle condivise consentono un comportamento simile a quello delle classi
  • __metatable protegge la metatabella dall'ispezione
  • __tostring controlla 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

  1. Introduzione alle metatabelle
  2. __index e __newindex
  3. Metametodi aritmetici
  4. __tostring e __len
← Torna a Lua Academy