__index et __newindex
Interceptez la lecture et l’écriture de champs avec les métaméthodes __index et __newindex.
__index et __newindex est une leçon Lua Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Lua Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Lua Academy comprend 4 leçons au total.
Récapitulatif de __index
__index est déclenché lorsque Lua tente de lire une clé qui n’existe pas dans la table. Il peut s’agir d’une table (recherche dans le prototype) ou d’une fonction (calcul dynamique). C’est la méthode de métatable la plus utilisée dans Lua : elle permet l’héritage, les valeurs par défaut et l’initialisation différée.
local defaults = {timeout=30, retries=3}
local config = setmetatable({timeout=60}, {__index=defaults})
print(config.timeout) -- 60 (own value)
print(config.retries) -- 3 (from defaults)
print(config.missing) -- nil (not in either)Déclenchement de __newindex
__newindex est déclenché lorsque Lua tente d’écrire une clé qui n’existe pas encore dans la table. Si la clé existe déjà, l’affectation s’effectue directement sans déclencher __newindex.
local proxy = setmetatable({}, {
__newindex = function(t, k, v)
print("New key:", k, "=", v)
rawset(t, k, v) -- actually store it
end
})
proxy.x = 10 -- New key: x = 10
proxy.x = 20 -- no trigger! x already exists
print(proxy.x) -- 20Tables en lecture seule
Utilisez __newindex pour créer des tables en lecture seule. Interceptez toutes les écritures et déclenchez une erreur. Combinez-le avec __index pour fournir des valeurs sans les stocker directement dans la table.
local function readOnly(t)
return setmetatable({}, {
__index = t,
__newindex = function(_, k, _)
error("attempt to write to read-only table key: " .. tostring(k), 2)
end
})
end
local cfg = readOnly({host="localhost", port=8080})
print(cfg.host) -- localhost
-- cfg.host = "x" -- ERROR: attempt to write to read-only tableSuivre les modifications
Utilisez __newindex pour suivre toutes les modifications d’une table — ce qui est utile pour le débogage, la journalisation des modifications ou les liaisons de données réactives. Stockez les données dans une table « support » masquée et enregistrez les modifications dans un journal.
local log = {}
local data = {}
local tracked = setmetatable({}, {
__index = data,
__newindex = function(_, k, v)
log[#log+1] = {key=k, old=data[k], new=v}
data[k] = v
end
})
tracked.name = "Alice"
tracked.age = 30
tracked.name = "Bob"
for _, entry in ipairs(log) do
print(entry.key, entry.old, "->", entry.new)
endObjets proxy
Un proxy enveloppe un autre objet afin d’intercepter toutes les lectures et écritures. Utilisez une table vide comme proxy, avec __index et __newindex pointant tous deux vers des fonctions. Les données réelles se trouvent dans une table distincte.
local function makeProxy(target)
return setmetatable({}, {
__index = function(_, k) return target[k] end,
__newindex = function(_, k, v)
print("Setting", k, "on target")
target[k] = v
end,
})
end
local real = {x=10}
local p = makeProxy(real)
print(p.x) -- 10 (reads from real)
p.y = 20 -- Setting y on target
print(real.y) -- 20Chaînage de __index (héritage)
Le chaînage des métatables __index crée un héritage fondé sur les prototypes. Lorsqu’une clé est introuvable dans l’objet, Lua vérifie la classe, puis la classe parente, et ainsi de suite. Chaque niveau a besoin de sa propre métatable, dont __index pointe vers le niveau suivant.
local Base = {type = "base", version = 1}
local Child = setmetatable({type = "child"}, {__index = Base})
local Obj = setmetatable({}, {__index = Child})
print(Obj.type) -- base? No: child (Child has it)
print(Obj.version) -- 1 (from Base)
print(Obj.type) -- child (Child overrides Base.type)Initialisation différée avec __index
Utilisez un __index sous forme de fonction pour calculer et mettre en cache des valeurs coûteuses lors du premier accès. Lors de la première lecture, calculez la valeur et stockez-la directement dans la table (ce qui évite les futurs appels à __index).
local lazy = setmetatable({}, {
__index = function(t, k)
if k == "expensiveData" then
print("Computing...")
local result = {1,2,3,4,5} -- simulate work
rawset(t, k, result)
return result
end
end
})
print(lazy.expensiveData) -- Computing... then table
print(lazy.expensiveData) -- (no "Computing" this time)__newindex pour valider un schéma
Utilisez __newindex pour imposer un schéma : n’autorisez la définition que de clés prédéfinies ou de valeurs du type correct. Cela ajoute une légère sécurité de typage aux tables Lua.
local schema = {name="string", age="number", active="boolean"}
local function schemaTable()
local store = {}
return setmetatable({}, {
__index = store,
__newindex = function(_, k, v)
local expected = schema[k]
if not expected then error("unknown key: "..k,2) end
if type(v) ~= expected then
error(k.." must be "..expected..", got "..type(v),2)
end
store[k] = v
end
})
end
local user = schemaTable()
user.name = "Alice"
user.age = 30
-- user.age = "thirty" -- ERROR__index contre rawget
Dans une fonction __index, utilisez rawget pour lire la table sans déclencher à nouveau __index (ce qui provoquerait une récursion infinie). Utilisez toujours rawget/rawset dans les méthodes de métatable pour manipuler le stockage réel de la table.
local counter = setmetatable({count=0}, {
__index = function(t, k)
-- Use rawget to avoid recursion
local c = rawget(t, "count")
rawset(t, "count", c + 1)
return rawget(t, k)
end
})
print(counter.count) -- 0 (direct, no __index)
print(counter.missing) -- nil
print(counter.count) -- 1 (incremented)Combiner __index et __newindex
Le modèle le plus puissant consiste à utiliser une table proxy vide avec __index et __newindex, soutenue par une table de données masquée. Vous contrôlez ainsi entièrement les lectures et les écritures, ce qui permet notamment de détecter les modifications, de charger les données à la demande et de contrôler les accès.
local function observable(init)
local data = init or {}
local listeners = {}
local obj = setmetatable({}, {
__index = data,
__newindex = function(_, k, v)
local old = data[k]
data[k] = v
for _, cb in ipairs(listeners) do cb(k,old,v) end
end
})
obj._onchange = function(_, cb) listeners[#listeners+1]=cb end
return obj
end
local obs = observable({score=0})
obs:_onchange(function(k,o,n) print(k,o,"->",n) end)
obs.score = 100 -- score 0 -> 100Vérification rapide
Dans quel cas __newindex n’est-il NOT pas déclenché ?
Récapitulatif : __index et __newindex
Points essentiels :
__index: déclenché lors de la lecture d’une clé absente ; table ou fonction__newindex: déclenché uniquement lors de l’écriture d’une nouvelle clé- Utilisez
rawget/rawsetdans les méthodes de métatable pour éviter la récursion - Modèles : tables en lecture seule, suivi des modifications, initialisation différée, validation de schéma
- Proxy vide + table support = interception complète des lectures et écritures
Questions Fréquemment Posées
La leçon « __index et __newindex » est-elle gratuite ?
Oui — le texte complet de « __index et __newindex » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Lua Academy, passe à CoddyKit PRO. Le cours Lua Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « __index et __newindex » ?
Interceptez la lecture et l’écriture de champs avec les métaméthodes __index et __newindex. Tu pratiques Lua Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Lua Academy ?
Aucune expérience préalable n'est requise. Lua Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « __index et __newindex » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Lua Academy ?
Oui. Chaque leçon Lua Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Introduction aux métatables
- __index et __newindex
- Métaméthodes arithmétiques
- __tostring et __len