El metamétodo __newindex
Parte de la sección Logic & Flow del Journey de Lua de Coddy — lección 19 de 54.
Has aprendido cómo __index controla lo que sucede cuando intentas leer una clave que no existe en una tabla. Ahora descubrirás su contraparte: __newindex, que controla lo que sucede cuando intentas añadir o modificar un par clave-valor.
El metamétodo __newindex se activa cada vez que intentas asignar un valor a una clave que no existe actualmente en la tabla. Esto te da el poder de interceptar y controlar las modificaciones antes de que ocurran.
Aquí tienes un ejemplo sencillo que evita que se añadan nuevas claves a una tabla:
local readOnly = {}
local meta = {
__newindex = function(table, key, value)
print("Cannot add key: " .. key)
end
}
setmetatable(readOnly, meta)
readOnly.name = "Alice" -- Salida: Cannot add key: name
print(readOnly.name) -- Salida: nilCuando intentas establecer readOnly.name = "Alice", Lua ve que name no existe en la tabla. En lugar de añadirlo, Lua llama a la función __newindex con tres argumentos: la propia tabla, la clave que se está estableciendo y el valor que se está asignando.
En este ejemplo, la función simplemente imprime un mensaje y en realidad no almacena nada.
También puedes usar __newindex para validar datos antes de permitirlos en tu tabla:
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" -- Salida: Health must be a number!
player.health = 100 -- PermitidoObserve el uso de rawset() en el segundo ejemplo. Esta función omite la metatabla y establece directamente el valor en la tabla.
Sin ello, establecer el valor activaría __newindex de nuevo, creando un bucle infinito.
Desafío
FácilEscribe una función createValidatedTable que reciba key y value y devuelva una tabla que solo acepte valores de tipo string para nuevas claves.
Crea una tabla vacía y adjunta una metatabla con __newindex que valide el tipo de valor. Si alguien intenta agregar un valor que no sea un string, usa rawset() para almacenar el string "invalid" en su lugar. Para valores de tipo string, almacénalos normalmente usando rawset().
Lógica:
- Crea una tabla vacía
- Crea una metatabla con
__newindexque reciba la tabla, la clave y el valor - Dentro de
__newindex, verifica si el valor es un string usandotype(value) == "string" - Si es un string, usa
rawset(t, key, value)para almacenarlo - Si no es un string, usa
rawset(t, key, "invalid")para almacenar"invalid"en su lugar - Adjunta la metatabla a la tabla usando
setmetatable() - Usa
rawset()para agregar el par clave-valor inicial a la tabla (omitiendo la metatabla) - Devuelve la tabla
Parámetros:
key(string): La clave inicial para agregar a la tablavalue(string): El valor inicial para agregar a la tabla
Devuelve: Una tabla con validación que solo acepta valores de tipo string, que contiene el par clave-valor inicial (table)
Hoja de referencia
El metamétodo __newindex se activa cuando intentas asignar un valor a una clave que no existe en una tabla, lo que te permite interceptar y controlar las modificaciones.
Ejemplo básico para prevenir nuevas claves:
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 función __newindex recibe tres argumentos: la propia tabla, la clave que se está estableciendo y el valor que se está asignando.
Validación de datos con __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 -- AllowedUsa rawset(t, key, value) para omitir la metatabla y establecer valores directamente en la tabla. Esto evita bucles infinitos al establecer valores dentro de __newindex.
Pruébalo tú mismo
function createValidatedTable(key, value)
-- Escribe el código aquí
end
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Logic & Flow
1Iteración avanzada de tablas
Iterar con pairs()Iterar con ipairs()pairs() vs. ipairs()Resumen - Ficha de personaje4Introducción a las Metatablas
¿Qué es una Metatabla?setmetatable y getmetatableEl metamétodo __indexEl metamétodo __newindexEl metamétodo __tostringMetamétodos aritméticos - Parte 1Metamétodos aritméticos - Parte 2Resumen - Tablas de solo lectura2Más funciones de la librería table
table.concat()Construcción de tablas y unpack()table.sort()Ordenamiento personalizado con funcionesRepaso - Tabla de puntuaciones altas