Essayez de donner la official source une lecture, en particulier §2.4 – Metatables and Metamethods
, et la description de la __index
methamethod, qui se lit comme suit:
__index: L'accès à l'indexation table[key]
. Cet événement se produit lorsque la table n'est pas une table ou lorsque la clé n'est pas présente dans la table. Le métaméthode est recherché dans le tableau.
Malgré le nom, le métaméthode de cet événement peut être une fonction ou une table. S'il s'agit d'une fonction, elle est appelée avec table et clé comme arguments, et le résultat de l'appel (ajusté à une valeur) est le résultat de l'opération. S'il s'agit d'une table, le résultat final est le résultat de l'indexation de cette table avec la clé. (Cette indexation est régulière, pas cru, et peut donc déclencher une autre métaméthode.)
Nous pouvons voir que votre pensée est à l'envers. Les propriétés d'une table référencée par le métaméthode __index
ne sont recherchées que si la table d'origine ne contient pas la clé.
Si vous voulez 'accrocher' une fonction, vous devrez l'écraser, en sauvegardant éventuellement l'original pour le restaurer plus tard. Si vous voulez coller fonctionnellement à une fonction existante, vous pouvez écrire une petite fonction d'accrochage, qui crée simplement une fermeture autour des fonctions, en les appelant tour à tour.
local function hook (original_fn, new_fn)
return function (...)
original_fn(...)
new_fn(...)
end
end
local test = {}
test.foo = function() print('hello') end
test.foo = hook(test.foo, function() print('world!') end)
test.foo() --> prints 'hello' then 'world!'
Vous pouvez basculer entre métatables, en supposant que la table d'origine ne remplace jamais les clés d'intérêt, pour obtenir des résultats différents:
local my_table, default, extra = {}, {}, {}
function default.foo() print('hello') end
function extra.foo() print('world!') end
local function set_mt (t, mt)
mt.__index = mt
return setmetatable(t, mt)
end
set_mt(my_table, default)
my_table.foo() --> prints 'hello'
set_mt(my_table, extra)
my_table.foo() --> prints 'world!'