Menu
CoddyTech

Il metametodo __newindex

Fa parte della sezione Logica e flusso del percorso Lua di Coddy. Lezione 19 di 54.

Hai imparato come __index controlla cosa succede quando provi a leggere una chiave che non esiste in una tabella. Ora scoprirai la sua controparte: __newindex, che controlla cosa succede quando assegni un valore a una chiave che la tabella non contiene ancora.

Il metametodo __newindex viene attivato ogni volta che tenti di assegnare un valore a una chiave che al momento non esiste nella tabella. Questo ti permette di intercettare e controllare le modifiche prima che avvengano.

Ecco un semplice esempio che impedisce di aggiungere nuove chiavi a una tabella:

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

Quando provi a impostare readOnly.name = "Alice", Lua vede che name non esiste nella tabella. Invece di aggiungerlo, Lua chiama la funzione __newindex con tre argomenti: la tabella stessa, la chiave da impostare e il valore assegnato.

In questo esempio, la funzione si limita a stampare un messaggio e in realtà non memorizza nulla.

Puoi anche usare __newindex per convalidare i dati prima di consentirne l'inserimento nella tabella:

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     -- Consentito, memorizzato con rawset
player.health = "high"  -- Nessun messaggio: health esiste già

Nota l’uso di rawset() nel secondo esempio. Questa funzione ignora la metatabella e imposta direttamente il valore nella tabella.

Senza di esso, impostare il valore attiverebbe di nuovo __newindex, creando un ciclo infinito.

Poiché __newindex viene eseguito solo per le chiavi che la tabella non possiede, questo controllo protegge la prima assegnazione di ogni chiave. Una volta che rawset ha memorizzato health, le assegnazioni successive la modificano direttamente. Per controllare ogni assegnazione, mantieni vuota la tabella stessa e memorizza i valori in una seconda tabella, a cui accede tramite __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"  -- Output: Health must be a number!
print(player.health)    -- Output: 100

player non ottiene mai una chiave propria, quindi ogni assegnazione passa attraverso __newindex e ogni lettura passa attraverso __index fino a data.

challenge icon

Sfida

Facile

Scrivi una funzione createValidatedTable che accetta key e value e restituisce una tabella che accetta solo valori stringa per le nuove chiavi.

Crea una tabella vuota e associa una metatabella con __newindex che convalida il tipo del valore. Se qualcuno prova ad aggiungere un valore non stringa, usa rawset() per memorizzare la stringa "invalid" al suo posto. Per i valori stringa, memorizzali normalmente usando rawset().

Logica:

  • Crea una tabella vuota
  • Crea una metatabella con __newindex che riceve la tabella, la chiave e il valore
  • All'interno di __newindex, verifica se il valore è una stringa usando type(value) == "string"
  • Se è una stringa, usa rawset(t, key, value) per memorizzarla
  • Se non è una stringa, usa rawset(t, key, "invalid") per memorizzare "invalid" al suo posto
  • Associa la metatabella alla tabella usando setmetatable()
  • Usa rawset() per aggiungere alla tabella la coppia chiave-valore iniziale (ignorando la metatabella)
  • Restituisci la tabella

Parametri:

  • key (stringa): la chiave iniziale da aggiungere alla tabella
  • value (stringa): il valore iniziale da aggiungere alla tabella

Valore restituito: una tabella con convalida che accetta solo valori stringa e contiene la coppia chiave-valore iniziale (tabella)

Provalo tu

function createValidatedTable(key, value)
    -- Scrivi il codice qui
end
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Logica e flusso

Esercitati da solo: Compilatore Lua online