A menudo queremos que las tablas se comporten de una «manera especial»: que se sumen como vectores, que sustituyan valores predeterminados, que se impriman de forma bonita. ✨ Para ello, Lua tiene metatables - guionistas ocultos del comportamiento de las tablas. A continuación se muestra un análisis breve, práctico y sencillo.

🧩 ¿Qué son las metatables?
Metatable — es una tabla normal adjunta a otra tabla a través de setmetatable(), que describe cómo responde un objeto a las operaciones: indexación, suma, comparación, concatenación, llamada, etc.
Piensa en la metatabla como una «capa de reglas»: Lua comprueba las claves y las operaciones y, si encuentra el metamétodo correspondiente (por ejemplo, __index), lo utiliza.
🧰 ¿Por qué es necesario?
Tarea | Metamétodo |
|---|---|
Valores predeterminados / prototipo |
|
Control/prohibición de grabación |
|
Redefinición de la suma/multiplicación/... |
|
Una bonita conclusión |
|
Comparación / longitud / concatenación |
|
Hacemos la tabla "llamada" |
|
Protegemos la metatabla |
|
El ejemplo más corto: sumar tablas como vectores
local mt = {
__add = function(a, b)
return { a[1] + b[1], a[2] + b[2] }
end
}
local v1 = setmetatable({1, 2}, mt)
local v2 = setmetatable({3, 4}, mt)
local sum = v1 + v2
print(sum[1], sum[2]) --> 4 6
Sin metatablas v1 + v2 causaría un error: Lua no sabe cómo añadir tablas.
🧭 __index: valores predeterminados y «herencia»
__index se activa cuando no hay clave en la tabla. Se puede establecer mediante una referencia a una tabla prototipo o una función.
Opción 1: prototipo
local defaults = { speed = 10, hp = 100 }
local player = setmetatable({}, { __index = defaults })
print(player.speed) --> 10 (берётся из defaults)
player.speed = 20 -- теперь свой speed у player
print(player.speed) --> 20
Opción 2: creación automática de valores (inicialización perezosa)
local counts = setmetatable({}, {
__index = function(t, key)
local v = 0
rawset(t, key, v) -- записываем сразу, чтобы дальше было «как будто существовало всегда»
return v
end
})
counts["apples"] = counts["apples"] + 1
print(counts["apples"]) --> 1
Usamos rawset para no llamar a __newindex y no entrar en una recursión.
🛡️ __newindex: control de grabación
local guarded = setmetatable({ x = 0, y = 0 }, {
__newindex = function(t, k, v)
if k == "x" or k == "y" then
rawset(t, k, v) -- безопасная запись без повторного вызова __newindex
else
error("You cannot add a new field: " .. tostring(k), 2)
end
end
})
guarded.x = 10 -- ок
guarded.title = "oops" -- ошибка
Un error común es escribir t[k] = v dentro de __newindex. Esto volverá a llamar a __newindex y dará lugar a una recursión. Utilice rawset.
⚠️ Trampas
Metatablas no se copian al copiar una tabla de forma superficial, vuelva a colgarla.
Las cadenas demasiado astutas
__indexhacen que la depuración sea más difícil. Mantenga el modelo simple.rawget/rawsetlos metamétodos de omisión son tanto una fortaleza como un riesgo. Úselos con cuidado.
🚀 Técnicas avanzadas de Metatables
📞 __call: creamos una «fábrica» de objetos
El metamétodo __call permite llamar a la tabla como una función, lo cual es conveniente para fábricas y DSL.
local greeter = setmetatable({}, {
__call = function(_, name) print("Hi, " .. name .. "!") end
})
greeter("Code") --> Привет, Кодик!
🔒 __metatable: protección contra cambios
Puedes ocultar los metamétodos reales y prohibir su cambio de la siguiente manera:
local obj = {}
local mt = { __metatable = "Access to the metatable is denied" }
setmetatable(obj, mt)
print(getmetatable(obj)) --> Доступ к метатаблице запрещён
-- getmetatable(obj).__index -- уже не получить
🎨 Bonita salida y operadores «mágicos»
local mt = {
__tostring = function(t) return ("Point(%d, %d)"):format(t.x, t.y) end,
__len = function(t) return math.sqrt(t.x*t.x + t.y*t.y) end, -- длина вектора через #
__eq = function(a,b) return a.x==b.x and a.y==b.y end,
__add = function(a,b) return setmetatable({x=a.x+b.x, y=a.y+b.y}, mt) end,
}
local p = setmetatable({x=3, y=4}, mt)
print(p) --> Point(3, 4)
print(#p) --> 5
💬 ¿Dónde aplicarías las metatables en tu juego de Roblox/Love2D, en el sistema de configuración o en mini-DSL?
📚 ¿Quieres profundizar en el tema?
En el anexo Kodik encontrarás tutoriales detallados sobre Lua, ejercicios paso a paso, análisis de errores y práctica cómoda directamente en tu teléfono o navegador.
Y si quieres estar al tanto de las noticias, nuevas características y materiales útiles, suscríbete a nuestro Canal de Telegram. Es acogedor, profesional y con amor por el código ❤️
