Lua - Métatables

Une métatable est une table qui aide à modifier le comportement d'une table à laquelle elle est attachée à l'aide d'un jeu de clés et des méta-méthodes associées. Ces méta-méthodes sont de puissantes fonctionnalités Lua qui permettent des fonctionnalités telles que -

  • Modification / ajout de fonctionnalités aux opérateurs sur les tables.

  • Recherche de métatables lorsque la clé n'est pas disponible dans la table à l'aide de __index dans métatable.

Il existe deux méthodes importantes utilisées pour gérer les métatables, notamment:

  • setmetatable(table,metatable) - Cette méthode est utilisée pour définir métatable pour une table.

  • getmetatable(table) - Cette méthode est utilisée pour obtenir la métatable d'une table.

Voyons d'abord comment définir une table comme métatable d'une autre. Il est montré ci-dessous.

mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)

Le code ci-dessus peut être représenté sur une seule ligne comme indiqué ci-dessous.

mytable = setmetatable({},{})

_indice

Un exemple simple de métatable permettant de rechercher la méta-table lorsqu'elle n'est pas disponible dans le tableau est illustré ci-dessous.

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)

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons la sortie suivante.

value1 metatablevalue

Expliquons par étapes ce qui s'est passé dans l'exemple ci-dessus.

  • Le tableau mytable ici est {key1 = "value1"}.

  • Metatable est défini pour mytable qui contient une fonction pour __index, que nous appelons une métaméthode.

  • La métaméthode fait un simple travail de recherche d'un index "key2", s'il est trouvé, il retourne "metatablevalue", sinon retourne la valeur de mytable pour l'index correspondant.

Nous pouvons avoir une version simplifiée du programme ci-dessus comme indiqué ci-dessous.

mytable = setmetatable({key1 = "value1"}, 
   { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)

__newindex

Lorsque nous ajoutons __newindex à metatable, si les clés ne sont pas disponibles dans la table, le comportement des nouvelles clés sera défini par des méta-méthodes. Un exemple simple où l'index de metatable est défini lorsque l'index n'est pas disponible dans la table principale est donné ci-dessous.

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)

Lorsque vous exécutez le programme ci-dessus, vous obtenez la sortie suivante.

value1
nil	new value 2
new  value 1	nil

Vous pouvez voir dans le programme ci-dessus, si une clé existe dans la table principale, elle la met simplement à jour. Lorsqu'une clé n'est pas disponible dans le maintable, il ajoute cette clé au métatable.

Un autre exemple qui met à jour la même table à l'aide de la fonction rawset est illustré ci-dessous.

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)

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons la sortie suivante.

new value	"4"

rawset définit la valeur sans utiliser __newindex de métatable. De même, il y a rawget qui obtient de la valeur sans utiliser __index.

Ajout d'un comportement d'opérateur aux tables

Un exemple simple pour combiner deux tables à l'aide de l'opérateur + est présenté ci-dessous -

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

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons la sortie suivante.

1	1
2	2
3	3
4	4
5	5
6	6

La clé __add est incluse dans la métatable pour ajouter le comportement de operator +. Le tableau des touches et de l'opérateur correspondant est présenté ci-dessous.

N ° Sr. Mode et description
1

__add

Modifie le comportement de l'opérateur «+».

2

__sub

Modifie le comportement de l'opérateur «-».

3

__mul

Modifie le comportement de l'opérateur «*».

4

__div

Modifie le comportement de l'opérateur «/».

5

__mod

Modifie le comportement de l'opérateur '%'.

6

__unm

Modifie le comportement de l'opérateur «-».

sept

__concat

Modifie le comportement de l'opérateur «..».

8

__eq

Modifie le comportement de l'opérateur '=='.

9

__lt

Modifie le comportement de l'opérateur «<».

dix

__le

Modifie le comportement de l'opérateur '<='.

__appel

L'ajout du comportement de l'appel de méthode se fait à l'aide de l'instruction __call. Un exemple simple qui renvoie la somme des valeurs de la table principale avec la table passée.

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

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons la sortie suivante.

70

__tostring

Pour modifier le comportement de l'instruction d'impression, nous pouvons utiliser la métaméthode __tostring. Un exemple simple est présenté ci-dessous.

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)

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons la sortie suivante.

The sum of values in the table is 60

Si vous connaissez parfaitement les capacités de la méta-table, vous pouvez vraiment effectuer de nombreuses opérations qui seraient très complexes sans l'utiliser. Alors, essayez de travailler davantage sur l'utilisation des métatables avec différentes options disponibles dans les méta-tables comme expliqué dans les exemples et créez également vos propres échantillons.