Menu
Coddy logo textTech

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 : nil

Lorsque 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.

challenge icon

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 __newindex qui reçoit la table, la clé et la valeur
  • À l'intérieur de __newindex, vérifiez si la valeur est une chaîne en utilisant type(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 table
  • value (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: nil

La 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     -- Allowed

Utilisez 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
quiz iconTestez-vous

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