Nous voulons souvent que les tableaux se comportent « d'une manière spéciale » : qu'ils s'additionnent comme des vecteurs, qu'ils remplacent les valeurs par défaut, qu'ils s'impriment magnifiquement. ✨ Pour cela, Lua a metatables - scénaristes cachés du comportement des tableaux. Ci-dessous, une analyse brève, pratique et indolore.

🧩 Que sont les metatables
Metatable — il s'agit d'une table ordinaire attachée à une autre table via setmetatable(), qui décrit comment l'objet réagit aux opérations : indexation, addition, comparaison, concaténation, appel, etc.
Considérez la métatable comme une « couche de règles » : Lua vérifie les clés et les opérations et, s'il trouve une métaméthode correspondante (par exemple, __index), il l'utilise.
🧰 Pourquoi est-ce nécessaire
Tâche | Métaméthode |
|---|---|
Valeurs par défaut/prototype |
|
Contrôle / interdiction d'enregistrement |
|
Redéfinition de l'addition / multiplication / ... |
|
Belle conclusion |
|
Comparaison / longueur / concaténation |
|
Créons un tableau « appelé » |
|
Protéger la métatable |
|
L'exemple le plus court : l'addition de tableaux en tant que vecteurs
local mt = {
__add = function(a, b)
return { a[1] + b[1], a[2] + b[2] }
end
}
local v1 = setmetatable({1, 2}, mt)
local v2 = setmetatable({3, 4}, mt)
local sum = v1 + v2
print(sum[1], sum[2]) --> 4 6
Sans les métatables v1 + v2 cela provoquerait une erreur : Lua ne sait pas comment ajouter des tables.
🧭 __index : valeurs par défaut et « héritage »
__index se déclenche lorsqu'il n'y a pas de clé dans le tableau. Il peut être défini par une référence à une table prototype ou à une fonction.
Option 1 : prototype
local defaults = { speed = 10, hp = 100 }
local player = setmetatable({}, { __index = defaults })
print(player.speed) --> 10 (берётся из defaults)
player.speed = 20 -- теперь свой speed у player
print(player.speed) --> 20
Option 2 : création automatique de valeurs (initialisation paresseuse)
local counts = setmetatable({}, {
__index = function(t, key)
local v = 0
rawset(t, key, v) -- записываем сразу, чтобы дальше было «как будто существовало всегда»
return v
end
})
counts["apples"] = counts["apples"] + 1
print(counts["apples"]) --> 1
Nous utilisons rawset pour ne pas appeler __newindex et ne pas tomber dans la récursion.
🛡️ __newindex : contrôle de l'enregistrement
local guarded = setmetatable({ x = 0, y = 0 }, {
__newindex = function(t, k, v)
if k == "x" or k == "y" then
rawset(t, k, v) -- безопасная запись без повторного вызова __newindex
else
error("You cannot add a new field: " .. tostring(k), 2)
end
end
})
guarded.x = 10 -- ок
guarded.title = "oops" -- ошибка
Une erreur courante est d'écrire t[k] = v à l'intérieur de __newindex. Cela appellera à nouveau __newindex et conduira à une récursion. Utilisez rawset.
⚠️ Pièges
Méta-tableaux ne sont pas copiés lors de la copie de surface du tableau, accrochez à nouveau.
Les chaînes trop astucieuses
__indexrendent le débogage difficile. Gardez le modèle simple.rawget/rawsetcontourner les métaméthodes est à la fois une force et un risque. Utilisez-les consciemment.
🚀 Techniques avancées de Metatables
📞 __call : créer une « usine » d'objets
La métaméthode __call vous permet d'appeler une table en tant que fonction, ce qui est pratique pour les fabriques et les DSL.
local greeter = setmetatable({}, {
__call = function(_, name) print("Hi, " .. name .. "!") end
})
greeter("Code") --> Привет, Кодик!
🔒 __metatable : protection contre les modifications
Vous pouvez cacher les métaméthodes réelles et interdire leur modification de la manière suivante :
local obj = {}
local mt = { __metatable = "Access to the metatable is denied" }
setmetatable(obj, mt)
print(getmetatable(obj)) --> Доступ к метатаблице запрещён
-- getmetatable(obj).__index -- уже не получить
🎨 Belle conclusion et opérateurs « magiques »
local mt = {
__tostring = function(t) return ("Point(%d, %d)"):format(t.x, t.y) end,
__len = function(t) return math.sqrt(t.x*t.x + t.y*t.y) end, -- длина вектора через #
__eq = function(a,b) return a.x==b.x and a.y==b.y end,
__add = function(a,b) return setmetatable({x=a.x+b.x, y=a.y+b.y}, mt) end,
}
local p = setmetatable({x=3, y=4}, mt)
print(p) --> Point(3, 4)
print(#p) --> 5
💬 Où appliqueriez-vous les metatables : dans un jeu Roblox/Love2D, dans un système de configuration ou dans un mini‑DSL ?
📚 Vous voulez approfondir le sujet ?
Dans l'application Code vous trouverez des leçons détaillées sur Lua, des exercices étape par étape, des analyses d'erreurs et des exercices pratiques directement sur votre téléphone ou votre navigateur.
Et si vous voulez être au courant des nouveautés, des nouvelles fonctionnalités et des contenus utiles, abonnez-vous à notre Chaîne Telegram. C'est confortable, professionnel et avec amour pour le code ❤️
