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.