Métatable Lua
Dans une table Lua, nous pouvons accéder à la clé correspondante pour obtenir la valeur, mais nous ne pouvons pas effectuer d'opérations sur deux tables (comme l'addition).
Par conséquent, Lua fournit des métatables, ce qui nous permet de modifier le comportement des tables. Chaque comportement est associé à une métaméthode correspondante.
Par exemple, en utilisant des métatables, nous pouvons définir comment Lua calcule l'opération d'addition a+b de deux tables.
Lorsque Lua essaie d'additionner deux tables, il vérifie d'abord si l'une d'elles possède une métatable, puis vérifie s'il existe un champ appelé__addSi trouvé, la valeur correspondante est appelée.__addDes champs comme ceux-ci ; leurs valeurs correspondantes (souvent une fonction ou une table) sont les « métaméthodes ».
Il existe deux fonctions très importantes pour gérer les métatables :
- setmetatable(table,metatable):Définit la métatable pour la table spécifiée. Si la métatable contient une clé __metatable, setmetatable échouera.
- getmetatable(table):Renvoie la métatable de l'objet.
L'exemple suivant montre comment définir une métatable pour une table spécifiée :
mymetatable = {} -- Métatable
setmetatable(mytable,mymetatable) -- Définir mymetatable comme la métatable de mytable
Le code ci-dessus peut également s'écrire sur une seule ligne :
mytable = setmetatable({},{})
Ce qui suit renvoie la métatable d'un objet :
getmetatable(mytable) -- 这会返回 mymetatable
métaméthode __index
C'est la clé la plus couramment utilisée dans une métatable.
Lorsque vous accédez à une table par clé, si la clé n'a pas de valeur, Lua recherchera la clé __index dans la métatable de la table (en supposant qu'il y ait une métatable). Si __index contient une table, Lua recherche la clé correspondante dans cette table.
Nous pouvons utiliser la commande lua pour entrer en mode interactif et vérifier :
Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
> other = { foo = 3 }
> t = setmetatable({}, { __index = other })
> t.foo
3
> t.bar
nil
Si __index contient une fonction, Lua appellera cette fonction, en passant la table et la clé comme arguments à la fonction.
La métaméthode __index vérifie si un élément existe dans la table. S'il n'existe pas, le résultat renvoyé est nil ; s'il existe, le résultat est renvoyé par __index.
Exemple
__index = function(mytable, key)
if key == "key2" then
return "metatablevalue"
else
return nil
end
end
})
print(mytable.key1,mytable.key2)
La sortie de l'exemple est :
value1 metatablevalue
Analyse de l'exemple :
La table mytable est assignée comme{key1 = "value1"}。
mytable a une métatable définie, et la métaméthode est __index.
Recherchez key1 dans la table mytable. S'il est trouvé, retournez l'élément ; sinon, continuez.
Recherchez key2 dans la table mytable. S'il est trouvé, retournez metatablevalue ; sinon, continuez.
Déterminez si la métatable possède une méthode __index. Si la méthode __index est une fonction, appelez cette fonction.
Dans la métaméthode, vérifiez si le paramètre de clé "key2" est passé (mytable.key2 est défini). Si le paramètre "key2" est passé, retournez "metatablevalue" ; sinon, retournez la valeur correspondante de mytable pour la clé.
Nous pouvons réécrire le code ci-dessus simplement comme suit :
print(mytable.key1,mytable.key2)
Résumé
Les règles lorsque Lua recherche un élément de table sont en fait les 3 étapes suivantes :
- 1. Recherchez dans la table. Si trouvé, retournez l'élément ; sinon, continuez.
- 2. Déterminez si la table possède une métatable. Si elle n'a pas de métatable, retournez nil ; si elle a une métatable, continuez.
- 3. Déterminez si la métatable possède une méthode __index. Si la méthode __index est nil, retournez nil ; si la méthode __index est une table, répétez les étapes 1, 2 et 3 ; si la méthode __index est une fonction, retournez la valeur de retour de cette fonction.
Cette partie provient de l'auteur Huanzi : https://blog.csdn.net/xocoder/article/details/9028347
métaméthode __newindex
La métaméthode __newindex est utilisée pour mettre à jour les tables, tandis que __index sert à accéder aux tables.
Lorsque vous affectez une valeur à un index inexistant d'une table, l'interpréteur recherche la métaméthode __newindex : si elle existe, il appelle cette fonction sans effectuer l'affectation.
L'exemple suivant illustre l'application de la métaméthode __newindex :
Exemple
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.key1)
La sortie après l'exécution de l'exemple ci-dessus est :
value1 nil 新值2 新值1 nil
Dans l'exemple ci-dessus, la table a la métaméthode __newindex définie. Lors de l'affectation à une nouvelle clé d'index (newkey) (mytable.newkey = "new value 2"), la métaméthode est appelée et l'affectation n'est pas effectuée. Lors de l'affectation à une clé d'index existante (key1), l'affectation est effectuée et la métaméthode __newindex n'est pas appelée.
L'exemple suivant utilise la fonction rawset pour mettre à jour une table :
Exemple
__newindex = function(mytable, key, value)
rawset(mytable, key, "\""..value.."\"")
end
})
mytable.key1 = "new value"
mytable.key2 = 4
print(mytable.key1,mytable.key2)
La sortie après l'exécution de l'exemple ci-dessus est :
new value "4"
Ajout d'opérateurs aux tables
L'exemple suivant démontre l'addition de deux tables :
Exemple
function table_maxn(t)
local mn = 0
for k, _ in pairs(t) do
if type(k) == "number" and k > mn then
mn = k
end
end
return mn
end
-- Opération d'addition de deux tables
mytable = setmetatable({ 1, 2, 3 }, {
__add = function(mytable, newtable)
local max_key_mytable = table_maxn(mytable)
for i = 1, table_maxn(newtable) do
table.insert(mytable, max_key_mytable + i, newtable[i])
end
return mytable
end
})
secondtable = {4, 5, 6}
mytable = mytable + secondtable
for k, v in ipairs(mytable) do
print(k, v)
end
La sortie après l'exécution de l'exemple ci-dessus est :
1 1 2 2 3 3 4 4 5 5 6 6
La clé __add est incluse dans la métatable et effectue l'opération d'addition. La liste des opérations correspondantes dans la table est la suivante : (Remarque :__il y a deux traits de soulignement)
| Modèle | Description |
|---|---|
| __add | Opérateur correspondant '+'. |
| __sub | Opérateur correspondant '-'. |
| __mul | Opérateur correspondant '*'. |
| __div | Opérateur correspondant '/'. |
| __mod | Opérateur correspondant '%'. |
| __unm | Opérateur correspondant '-'. |
| __concat | Opérateur correspondant '..'. |
| __eq | Opérateur correspondant '=='. |
| __lt | Opérateur correspondant '<'. |
| __le | Opérateur correspondant '<='. |
Métaméthode __call
La métaméthode __call est appelée lorsque Lua appelle une valeur. L'exemple suivant montre comment calculer la somme des éléments d'une table :
Exemple
-- Fonction personnalisée table_maxn pour calculer la valeur de clé maximale dans une table, c'est-à-dire calculer le nombre d'éléments dans la table
function table_maxn(t)
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
-- Définir la métaméthode __call
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))
La sortie après l'exécution de l'exemple ci-dessus est :
70
métaméthode __tostring
La métaméthode __tostring est utilisée pour modifier le comportement de sortie d'une table. Dans l'exemple suivant, nous personnalisons le contenu de sortie d'une table :
Exemple
__tostring = function(mytable)
sum = 0
for k, v in pairs(mytable) do
sum = sum + v
end
return "La somme de tous les éléments de la table est " .. sum
end
})
print(mytable)
La sortie après l'exécution de l'exemple ci-dessus est :
表所有元素的和为 60
Grâce à cet article, nous pouvons apprendre que les métatables peuvent efficacement simplifier les fonctionnalités de notre code, donc comprendre les métatables de Lua peut nous aider à écrire un code Lua plus simple et meilleur.
Autres extensions