Lua - Metatables
Un metatable è una tabella che aiuta a modificare il comportamento di una tabella a cui è collegata con l'aiuto di un set di chiavi e dei relativi meta metodi. Questi meta metodi sono potenti funzionalità Lua che abilitano funzionalità come:
Modifica / aggiunta di funzionalità agli operatori sulle tabelle.
Ricerca di metatables quando la chiave non è disponibile nella tabella utilizzando __index in metatable.
Esistono due metodi importanti utilizzati nella gestione dei metatables che includono:
setmetatable(table,metatable) - Questo metodo viene utilizzato per impostare metatable per una tabella.
getmetatable(table) - Questo metodo viene utilizzato per ottenere metatable di una tabella.
Diamo prima un'occhiata a come impostare una tabella come metatizzabile di un'altra. È mostrato di seguito.
mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)
Il codice sopra può essere rappresentato in una singola riga come mostrato di seguito.
mytable = setmetatable({},{})
_indice
Di seguito è mostrato un semplice esempio di metatable per cercare la meta tabella quando non è disponibile nella tabella.
mytable = setmetatable({key1 = "value1"}, {
__index = function(mytable, key)
if key == "key2" then
return "metatablevalue"
else
return mytable[key]
end
end
})
print(mytable.key1,mytable.key2)
Quando eseguiamo il programma precedente, otterremo il seguente output.
value1 metatablevalue
Cerchiamo di spiegare cosa è successo nell'esempio sopra nei passaggi.
Il tavolo mytable qui è {key1 = "value1"}.
Metatable è impostato per mytable che contiene una funzione per __index, che chiamiamo metamethod.
Il metametodo fa un semplice lavoro di ricerca di un indice "key2", se viene trovato, restituisce "metatablevalue", altrimenti restituisce il valore di mytable per l'indice corrispondente.
Possiamo avere una versione semplificata del programma sopra come mostrato di seguito.
mytable = setmetatable({key1 = "value1"},
{ __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)
__newindex
Quando aggiungiamo __newindex a metatable, se le chiavi non sono disponibili nella tabella, il comportamento delle nuove chiavi sarà definito dai meta metodi. Di seguito viene fornito un semplice esempio in cui l'indice di metatable è impostato quando l'indice non è disponibile nella tabella principale.
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = "new value 2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = "new value 1"
print(mytable.key1,mymetatable.newkey1)
Quando esegui il programma sopra, ottieni il seguente output.
value1
nil new value 2
new value 1 nil
Puoi vedere nel programma sopra, se una chiave esiste nella tabella principale, la aggiorna semplicemente. Quando una chiave non è disponibile nella tabella principale, aggiunge quella chiave al metatable.
Un altro esempio che aggiorna la stessa tabella utilizzando la funzione rawset è mostrato di seguito.
mytable = setmetatable({key1 = "value1"}, {
__newindex = function(mytable, key, value)
rawset(mytable, key, "\""..value.."\"")
end
})
mytable.key1 = "new value"
mytable.key2 = 4
print(mytable.key1,mytable.key2)
Quando eseguiamo il programma sopra, otterremo il seguente output.
new value "4"
rawset imposta il valore senza usare __newindex di metatable. Allo stesso modo c'è rawget che ottiene valore senza usare __index.
Aggiunta del comportamento dell'operatore alle tabelle
Di seguito è mostrato un semplice esempio per combinare due tabelle utilizzando l'operatore +:
mytable = setmetatable({ 1, 2, 3 }, {
__add = function(mytable, newtable)
for i = 1, table.maxn(newtable) do
table.insert(mytable, table.maxn(mytable)+1,newtable[i])
end
return mytable
end
})
secondtable = {4,5,6}
mytable = mytable + secondtable
for k,v in ipairs(mytable) do
print(k,v)
end
Quando eseguiamo il programma precedente, otterremo il seguente output.
1 1
2 2
3 3
4 4
5 5
6 6
La chiave __add è inclusa nel metatable per aggiungere il comportamento dell'operatore +. Di seguito è riportata la tabella dei tasti e dell'operatore corrispondente.
Sr.No. | Modalità e descrizione |
---|---|
1 | __add Modifica il comportamento dell'operatore "+". |
2 | __sub Modifica il comportamento dell'operatore "-". |
3 | __mul Modifica il comportamento dell'operatore "*". |
4 | __div Modifica il comportamento dell'operatore "/". |
5 | __mod Modifica il comportamento dell'operatore '%'. |
6 | __unm Modifica il comportamento dell'operatore "-". |
7 | __concat Modifica il comportamento dell'operatore "..". |
8 | __eq Modifica il comportamento dell'operatore "==". |
9 | __lt Modifica il comportamento dell'operatore "<". |
10 | __le Modifica il comportamento dell'operatore "<=". |
__chiamata
L'aggiunta del comportamento della chiamata al metodo viene eseguita utilizzando l'istruzione __call. Un semplice esempio che restituisce la somma dei valori nella tabella principale con la tabella passata.
mytable = setmetatable({10}, {
__call = function(mytable, newtable)
sum = 0
for i = 1, table.maxn(mytable) do
sum = sum + mytable[i]
end
for i = 1, table.maxn(newtable) do
sum = sum + newtable[i]
end
return sum
end
})
newtable = {10,20,30}
print(mytable(newtable))
Quando eseguiamo il programma precedente, otterremo il seguente output.
70
__accordare
Per cambiare il comportamento dell'istruzione print, possiamo usare il metametodo __tostring. Di seguito viene mostrato un semplice esempio.
mytable = setmetatable({ 10, 20, 30 }, {
__tostring = function(mytable)
sum = 0
for k, v in pairs(mytable) do
sum = sum + v
end
return "The sum of values in the table is " .. sum
end
})
print(mytable)
Quando eseguiamo il programma precedente, otterremo il seguente output.
The sum of values in the table is 60
Se conosci appieno le capacità della meta table, puoi davvero eseguire molte operazioni che sarebbero molto complesse senza usarla. Quindi, prova a lavorare di più sull'uso dei metatables con diverse opzioni disponibili nelle meta tabelle come spiegato negli esempi e crea anche i tuoi campioni.