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: nilQuando 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: 100player non ottiene mai una chiave propria, quindi ogni assegnazione passa attraverso __newindex e ogni lettura passa attraverso __index fino a data.
Sfida
FacileScrivi 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
__newindexche riceve la tabella, la chiave e il valore - All'interno di
__newindex, verifica se il valore è una stringa usandotype(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 tabellavalue(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
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Logica e flusso
1Iterazione avanzata delle tabelle
Iterare con pairs()Iterare con ipairs()pairs() vs. ipairs()Riepilogo - Scheda del personaggio4Introduzione alle metatabelle
Che cos’è una metatabella?setmetatable e getmetatableIl metametodo __indexIl metametodo __newindexIl metametodo __tostringMetametodi aritmetici - Parte 1Metametodi aritmetici - Parte 2Riepilogo - Tabella di sola lettura2Altre funzioni della libreria table
table.concat()Costruzione di tabelle e unpack()table.sort()Ordinamento personalizzato con funzioniRiepilogo - Tabellone dei punteggi più altiEsercitati da solo: Compilatore Lua online