La métaméthode __newindex
Fait partie de la section Logic & Flow du Journey Lua de Coddy — leçon 19 sur 54.
Vous avez appris comment __index contrôle ce qui se passe lorsque vous essayez de lire une clé qui n'existe pas dans une table. Maintenant, vous allez découvrir son homologue : __newindex, qui contrôle ce qui se passe lorsque vous essayez d'ajouter ou de modifier une paire clé-valeur.
La métaméthode __newindex est déclenchée chaque fois que vous tentez d'assigner une valeur à une clé qui n'existe pas actuellement dans la table. Cela vous donne le pouvoir 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 vous essayez de définir readOnly.name = "Alice", Lua voit 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é en cours de définition et la valeur en cours d'assignation.
Dans cet exemple, la fonction affiche simplement un message et ne stocke rien en réalité.
Vous pouvez également utiliser __newindex pour valider les données avant de les autoriser dans votre 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éRemarquez l'utilisation de rawset() dans le second 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.
Défi
FacileÉcrivez une fonction createValidatedTable qui prend key et value et retourne une table qui n'accepte que des valeurs de type chaîne de caractères pour les nouvelles clés.
Créez une table vide et attachez-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, utilisez rawset() pour stocker la chaîne "invalid" à la place. Pour les valeurs de type chaîne, stockez-les normalement en utilisant rawset().
Logique :
- Créez une table vide
- Créez une métatable avec
__newindexqui reçoit la table, la clé et la valeur - À l'intérieur de
__newindex, vérifiez si la valeur est une chaîne en utilisanttype(value) == "string" - Si c'est une chaîne, utilisez
rawset(t, key, value)pour la stocker - Si ce n'est pas une chaîne, utilisez
rawset(t, key, "invalid")pour stocker"invalid"à la place - Attachez la métatable à la table en utilisant
setmetatable() - Utilisez
rawset()pour ajouter la paire clé-valeur initiale à la table (en contournant la métatable) - Retournez la table
Paramètres :
key(string) : La clé initiale à ajouter à la tablevalue(string) : La valeur initiale à ajouter à la table
Retourne : Une table avec une validation qui n'accepte que des valeurs de type chaîne, contenant la paire clé-valeur initiale (table)
Aide-mémoire
La métaméthode __newindex est déclenchée lorsque vous tentez d'assigner une valeur à une clé qui n'existe pas dans une table, vous permettant ainsi d'intercepter et de contrôler les modifications.
Exemple de base empêchant l'ajout de nouvelles clés :
local readOnly = {}
local meta = {
__newindex = function(table, key, value)
print("Cannot add key: " .. key)
end
}
setmetatable(readOnly, meta)
readOnly.name = "Alice" -- Output: Cannot add key: name
print(readOnly.name) -- Output: nilLa fonction __newindex reçoit trois arguments : la table elle-même, la clé en cours de définition et la valeur assignée.
Validation de données avec __newindex :
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" -- Output: Health must be a number!
player.health = 100 -- AllowedUtilisez rawset(t, key, value) pour contourner la métatable et définir directement des valeurs dans la table. Cela évite les boucles infinies lors de la définition de valeurs à l'intérieur de __newindex.
Essayez vous-même
function createValidatedTable(key, value)
-- Écrire 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 Logic & Flow
1Itération avancée des tables
Itérer avec pairs()Itérer avec ipairs()pairs() vs. ipairs()Récapitulatif - Fiche de personnage2Plus de fonctions de la bibliothèque table
table.concat()Construction de table & unpack()table.sort()Tri personnalisé avec des fonctionsRécapitulatif - Tableau des scores3Concepts avancés sur les fonctions
Retourner plusieurs valeursFonctions variadiques (...)Les fonctions comme valeurs de première classeFonctions anonymesQu'est-ce qu'une closure ?Récapitulatif - Gestionnaire d'événements simple