La metaméthode __newindex
Fait partie de la section Logique et déroulement du programme du Journey Lua de Coddy. Leçon 19 sur 54.
Tu as appris comment __index contrôle ce qui se passe lorsque tu essaies de lire une clé qui n’existe pas dans une table. Tu vas maintenant découvrir son pendant : __newindex, qui contrôle ce qui se passe lorsque tu affectes une valeur à une clé que la table ne possède pas encore.
La métaméthode __newindex est déclenchée chaque fois que tu essaies d’assigner une valeur à une clé qui n’existe pas actuellement dans la table. Cela te permet d’intercepter et de contrôler les modifications avant qu’elles ne se produisent.
Voici un exemple simple qui empêche l’ajout de nouvelles clés à une table :
local readOnly = {}
local meta = {
__newindex = function(table, key, value)
print("Cannot add key: " .. key)
end
}
setmetatable(readOnly, meta)
readOnly.name = "Alice" -- Sortie : Cannot add key: name
print(readOnly.name) -- Sortie : nilLorsque tu essaies de définir readOnly.name = "Alice", Lua constate que name n’existe pas dans la table. Au lieu de l’ajouter, Lua appelle la fonction __newindex avec trois arguments : la table elle-même, la clé à définir et la valeur attribuée.
Dans cet exemple, la fonction affiche simplement un message et ne stocke rien en réalité.
Tu peux aussi utiliser __newindex pour valider les données avant de les laisser entrer dans ta table :
local player = {}
local meta = {
__newindex = function(t, key, value)
if key == "health" and type(value) ~= "number" then
print("Health must be a number!")
else
rawset(t, key, value)
end
end
}
setmetatable(player, meta)
player.health = "high" -- Sortie : Health must be a number!
player.health = 100 -- Autorisé, stocké avec rawset
player.health = "high" -- Aucun message : health existe maintenantRemarquez l’utilisation de rawset() dans le deuxième exemple. Cette fonction contourne la métatable et définit directement la valeur dans la table.
Sans cela, définir la valeur déclencherait à nouveau __newindex, créant une boucle infinie.
Comme __newindex ne s’exécute que pour les clés que la table ne possède pas, cette vérification protège la première affectation de chaque clé. Une fois que rawset a stocké health, les affectations suivantes la modifient directement. Pour vérifier chaque affectation, laisse la table elle-même vide et stocke les valeurs dans une seconde table, à laquelle elle accède par __index :
local data = {}
local player = setmetatable({}, {
__index = data,
__newindex = function(t, key, value)
if key == "health" and type(value) ~= "number" then
print("Health must be a number!")
else
data[key] = value
end
end
})
player.health = 100
player.health = "high" -- Sortie : Health must be a number!
print(player.health) -- Sortie : 100player n’obtient jamais de clé qui lui soit propre : chaque affectation passe donc par __newindex, et chaque lecture passe par __index pour accéder à data.
Défi
FacileÉcris une fonction createValidatedTable qui prend key et value et renvoie une table qui n’accepte que les valeurs de type chaîne pour les nouvelles clés.
Crée une table vide et associe-lui une métatable avec __newindex qui valide le type de la valeur. Si quelqu’un essaie d’ajouter une valeur qui n’est pas une chaîne, utilise rawset() pour stocker la chaîne "invalid" à la place. Pour les valeurs de type chaîne, stocke-les normalement avec rawset().
Logique :
- Crée une table vide
- Crée une métatable avec
__newindexqui reçoit la table, la clé et la valeur - Dans
__newindex, vérifie si la valeur est une chaîne à l’aide detype(value) == "string" - S’il s’agit d’une chaîne, utilise
rawset(t, key, value)pour la stocker - S’il ne s’agit pas d’une chaîne, utilise
rawset(t, key, "invalid")pour stocker"invalid"à la place - Associe la métatable à la table à l’aide de
setmetatable() - Utilise
rawset()pour ajouter la paire clé-valeur initiale à la table (en contournant la métatable) - Renvoie la table
Paramètres :
key(chaîne) : la clé initiale à ajouter à la tablevalue(chaîne) : la valeur initiale à ajouter à la table
Valeur de retour : une table avec une validation qui n’accepte que les valeurs de type chaîne et qui contient la paire clé-valeur initiale (table)
Essayez vous-même
function createValidatedTable(key, value)
-- Écrivez le code ici
end
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Logique et déroulement du programme
1Itération avancée des tables
Itérer avec pairs()Itérer avec ipairs()pairs() contre ipairs()Récapitulatif - Fiche de personnage2Fonctions supplémentaires de la bibliothèque table
table.concat()construction de tables et unpack()table.sort()Tri personnalisé avec des fonctionsRécapitulatif - Tableau des meilleurs scores3Concepts avancés des fonctions
Retourner plusieurs valeursFonctions variadiques (...)Les fonctions comme valeurs de première classeFonctions anonymesQu’est-ce qu’une fermeture ?Récapitulatif - Gestionnaire d’événements simpleEntraînez-vous par vous-même : Compilateur Lua en ligne