Lua métatable


Dans la table Lua nous pouvons accéder à la clé correspondante pour obtenir la valeur, mais nous ne pouvons pas opérer sur les deux tables.

Lua fournit donc une métatable (Metatable), qui nous permet de changer le comportement de la table. Chaque comportement est associé à la 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'ajouter deux tables, il vérifie d'abord si l'une des deux tables a une métatable, puis vérifie s'il existe un champ appelé "__add". S'il est trouvé, la valeur correspondante est appelée. Pour les champs temps réel tels que « __add », leur valeur correspondante (souvent une fonction ou une table) est une « méta-méthode ».

Il existe deux fonctions très importantes pour gérer les métatables :

  • setmetatable(table, métatable) : Définir la métatable pour la table spécifiée ( métatable) , si la valeur de clé __metatable existe dans la métatable (métatable), 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 :

mytable = {}                          -- 普通表 
mymetatable = {}                      -- 元表
setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表

Le code ci-dessus peut également être écrit directement sur une seule ligne :

mytable = setmetatable({},{})

Ce qui suit est renvoyé la métatable d'objet :

getmetatable(mytable)                 -- 这回返回mymetatable

métaméthode __index

Il s'agit de la clé de métatable la plus couramment utilisée.

Lorsque vous accédez à une table par clé, si la clé n'a aucune valeur, Lua cherchera 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 la table.


Nous pouvons utiliser la commande lua pour entrer en mode interactif pour afficher :

$ lua
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, et la table et la clé le feront be as Les paramètres sont transmis à la fonction.

La métaméthode __index vérifie si l'élément existe dans la table. S'il n'existe pas, le résultat renvoyé est nul s'il existe, le résultat est renvoyé par __index.

mytable = setmetatable({key1 = "value1"}, {
  __index = function(mytable, key)
    if key == "key2" then
      return "metatablevalue"
    else
      return nil
    end
  end
})

print(mytable.key1,mytable.key2)

Le résultat de la sortie de l'instance est :

value1	metatablevalue

Analyse de l'instance :

  • l'affectation de ma table est{key1 = "value1"}.

  • mytable définit la métatable et la métaméthode est __index.

  • Recherchez key1 dans la table mytable. Si trouvé, renvoyez l'élément. S'il n'est pas trouvé, continuez.

  • Recherchez key2 dans la table mytable. Si elle est trouvée, renvoyez la valeur métatable. Si elle n'est pas trouvée, continuez.

  • Déterminez si la métatable a une méthode __index Si la méthode __index est une fonction, appelez la fonction.

  • Dans la méthode méta, vérifiez si le paramètre clé "key2" est transmis (mytable.key2 a été défini. Si le paramètre "key2" est transmis, "metatablevalue"). est renvoyé, sinon la valeur correspondante de mytable est renvoyée.


Nous pouvons simplement écrire le code ci-dessus comme :

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

Résumé

Quand Lua recherche une table element Les règles sont en fait les 3 étapes suivantes :

  • 1. Rechercher dans le tableau, renvoyer l'élément. S'il n'est pas trouvé, continuer

    .
  • 2. Déterminez si la table a une métatable, s'il n'y a pas de métatable, renvoyez nil. S'il y a une métatable, continuez.

  • 3. Déterminez si la métatable a une méthode __index. Si la méthode __index est nulle, renvoyez nil si la méthode __index est une table, répétez 1, 2 et 3 ; la méthode __index est une fonction, la valeur de retour de la fonction est renvoyée.


Méta-méthode __newindex

La méta-méthode __newindex est utilisée pour mettre à jour la table, et __index est utilisée pour accéder à la table.

Lorsque vous attribuez une valeur à un index manquant de la table, l'interpréteur recherche la métaméthode __newindex : si elle existe, il appelle cette fonction sans effectuer l'affectation.

L'exemple suivant démontre l'application de la méta-méthode __newindex :

mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)

Le résultat d'exécution de l'exemple ci-dessus est :

value1
nil	新值2
新值1	nil

Dans l'exemple ci-dessus, la méta- La méthode __newindex est définie dans le tableau. Lors de l'attribution d'une valeur à une nouvelle clé d'index (newkey) (mytable.newkey = "new value 2"), la métaméthode sera appelée sans attribuer de valeur. Si la clé d'index existante (key1) est attribuée, la valeur sera attribuée sans appeler la méta-méthode __newindex.

L'exemple suivant utilise la fonction rawset pour mettre à jour la table :

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)

Le résultat de l'exécution de l'exemple ci-dessus est :

new value	"4"

Ajouter des opérateurs à la table

L'exemple suivant démontre l'opération d'addition de deux tables :

-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大值函数 table_maxn
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

-- 两表相加操作
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

Le résultat de 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 l'opération d'addition est effectuée. La liste des opérations correspondantes dans le tableau est la suivante :

模式描述
__add对应的运算符 '+'.
__sub对应的运算符 '-'.
__mul对应的运算符 '*'.
__div对应的运算符 '/'.
__mod对应的运算符 '%'.
__unm对应的运算符 '-'.
__concat对应的运算符 '..'.
__eq对应的运算符 '=='.
__lt对应的运算符 '<'.
__le对应的运算符 '<='.

__call métaméthode

__call métaméthode est appelée lorsque Lua appelle une valeur. L'exemple suivant montre le calcul de la somme des éléments du tableau :

-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大值函数 table_maxn
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

-- 定义元方法__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))

Le résultat de l'exécution de l'exemple ci-dessus est :

70

__tostring metamethod

__tostring la métaméthode est utilisée pour modifier le comportement de sortie de la table. Dans l'exemple suivant, nous avons personnalisé le contenu de sortie de la table :

mytable = setmetatable({ 10, 20, 30 }, {
  __tostring = function(mytable)
    sum = 0
    for k, v in pairs(mytable) do
		sum = sum + v
	end
    return "表所有元素的和为 " .. sum
  end
})
print(mytable)

Le résultat de sortie de l'exécution de l'exemple ci-dessus est :

表所有元素的和为 60

A partir de cet article, nous pouvons savoir que le métatable peut grandement simplifier nos fonctions de code. Par conséquent, comprendre la métatable de Lua nous permet d'écrire du code Lua plus simple et meilleur.