Constructores y new()
Escriba funciones constructoras que creen e inicialicen instancias.
Constructores y new() es una lección gratuita de Lua Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Lua Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Lua Academy incluye 4 lecciones en total.
Responsabilidad del constructor
Un constructor crea e inicializa una instancia. Recibe los valores iniciales, los valida, establece valores predeterminados para los campos ausentes y devuelve la nueva instancia. Un constructor bien diseñado garantiza que todas las instancias comiencen en un estado válido.
local Player = {}
Player.__index = Player
function Player.new(name, hp, mp)
assert(type(name)=="string" and name~="","need name")
return setmetatable({
name = name,
hp = hp or 100,
mp = mp or 50,
alive = true,
items = {},
}, Player)
end
local p = Player.new("Hero")
print(p.name, p.hp, p.mp) -- Hero 100 50Constructor fluido
Un constructor fluido devuelve self desde los métodos setter, lo que permite encadenar métodos durante la construcción. Este es el patrón builder en Lua.
local Config = {}
Config.__index = Config
function Config.new()
return setmetatable({_data={}}, Config)
end
function Config:set(k,v) self._data[k]=v; return self end
function Config:build() return self._data end
local cfg = Config.new()
:set("host","localhost")
:set("port",8080)
:set("debug",true)
:build()
print(cfg.host, cfg.port)Constructor de copia
Un constructor de copia crea una nueva instancia con los mismos valores que otra existente. Importante: use una copia superficial o profunda según si las tablas anidadas deben compartirse o ser independientes.
local function deepCopy(orig)
if type(orig)~="table" then return orig end
local copy = {}
for k,v in pairs(orig) do copy[deepCopy(k)]=deepCopy(v) end
return setmetatable(copy, getmetatable(orig))
end
local Item = {}
Item.__index = Item
function Item.new(name, stats)
return setmetatable({name=name, stats=stats or {}}, Item)
end
function Item:clone()
return deepCopy(self)
end
local sword = Item.new("Sword",{damage=50})
local clone = sword:clone()
clone.stats.damage = 30
print(sword.stats.damage) -- 50 (unchanged)Constructor con validación
Valide siempre las entradas del constructor. Lance errores descriptivos para las entradas no válidas en el nivel 2 (la responsabilidad es de quien llama). Esto detecta los errores pronto y genera mensajes de error útiles.
local Rectangle = {}
Rectangle.__index = Rectangle
function Rectangle.new(w, h)
assert(type(w)=="number" and w>0,"width must be positive number")
assert(type(h)=="number" and h>0,"height must be positive number")
return setmetatable({width=w, height=h}, Rectangle)
end
function Rectangle:area() return self.width * self.height end
function Rectangle:perimeter() return 2*(self.width+self.height) end
local r = Rectangle.new(5, 3)
print(r:area(), r:perimeter()) -- 15 16Patrón de valores predeterminados
Use una tabla de valores predeterminados para gestionar correctamente los parámetros opcionales del constructor. Esto evita largas cadenas de x = x or default y hace que los valores predeterminados sean explícitos y fáciles de cambiar.
local Sprite = {}
Sprite.__index = Sprite
local DEFAULTS = {x=0,y=0,rotation=0,scale=1,visible=true,alpha=1}
function Sprite.new(image, opts)
local cfg = opts or {}
local self = {image=image}
for k,v in pairs(DEFAULTS) do
self[k] = cfg[k] ~= nil and cfg[k] or v
end
return setmetatable(self, Sprite)
end
local s = Sprite.new("hero.png",{x=100,y=200})
print(s.x,s.y,s.scale) -- 100 200 1Métodos de fábrica estáticos
Una clase puede tener varios métodos de fábrica para distintos escenarios de creación. Esto es más limpio que sobrecargar un único constructor con muchos parámetros opcionales.
local Color = {}
Color.__index = Color
function Color.fromRGB(r,g,b)
return setmetatable({r=r,g=g,b=b}, Color)
end
function Color.fromHex(hex)
hex = hex:gsub("#","")
return setmetatable({
r=tonumber(hex:sub(1,2),16),
g=tonumber(hex:sub(3,4),16),
b=tonumber(hex:sub(5,6),16),
}, Color)
end
function Color:toHex()
return string.format("#%02X%02X%02X",self.r,self.g,self.b)
end
local red = Color.fromHex("#FF0000")
print(red:toHex()) -- #FF0000Registro de constructores
Use un registro para realizar un seguimiento de todas las instancias. Esto permite operaciones globales como «destruir todas» o iterar sobre todos los objetos de un tipo.
local Enemy = {}
Enemy.__index = Enemy
Enemy._all = {}
function Enemy.new(name, hp)
local self = setmetatable({name=name, hp=hp}, Enemy)
Enemy._all[#Enemy._all+1] = self
return self
end
function Enemy.destroyAll()
for _, e in ipairs(Enemy._all) do
print("Destroying:", e.name)
end
Enemy._all = {}
end
Enemy.new("Goblin",30)
Enemy.new("Orc",80)
print("Count:", #Enemy._all) -- 2
Enemy.destroyAll()Inicialización diferida
Algunos campos son costosos de calcular. Use __index con una función para calcularlos y almacenarlos en caché la primera vez que se acceda a ellos.
local BigData = {}
BigData.__index = function(t, k)
if k == "processed" then
print("Computing processed...")
local result = {}
for i,v in ipairs(rawget(t,"raw")) do result[i]=v*2 end
rawset(t,"processed",result)
return result
end
end
function BigData.new(raw)
return setmetatable({raw=raw}, BigData)
end
local d = BigData.new({1,2,3,4,5})
print(d.processed[3]) -- Computing... 6
print(d.processed[3]) -- 6 (cached, no recompute)Prototipo a partir de una instancia
Clone una instancia para crear otra con los mismos valores base. El clon obtiene la misma metatabla (la misma clase) y una copia de los datos de la instancia. Resulta útil para objetos «plantilla».
local Unit = {}
Unit.__index = Unit
function Unit.new(t)
return setmetatable({name=t.name,hp=t.hp,atk=t.atk}, Unit)
end
function Unit:clone()
return Unit.new({name=self.name,hp=self.hp,atk=self.atk})
end
function Unit:__tostring()
return self.name.."(HP:"..self.hp..",ATK:"..self.atk..")"
end
local template = Unit.new({name="Soldier",hp=100,atk=10})
local u1 = template:clone(); u1.name="Alpha"
local u2 = template:clone(); u2.name="Beta"
print(tostring(u1),tostring(u2))Seguridad ante errores del constructor
Si la construcción falla a mitad del proceso (por ejemplo, al asignar un recurso), asegúrese de que no se escape ningún objeto parcial. Use pcall para capturar los errores de construcción y liberar los recursos si es necesario.
local FileHandle = {}
FileHandle.__index = FileHandle
function FileHandle.new(path, mode)
local f, err = io.open(path, mode or "r")
if not f then
return nil, "cannot open " .. path .. ": " .. err
end
return setmetatable({_f=f, path=path}, FileHandle)
end
function FileHandle:read(fmt) return self._f:read(fmt) end
function FileHandle:close() self._f:close() end
local fh, err = FileHandle.new("data.txt")
if not fh then print("Error:", err)
else print(fh:read("l")); fh:close()
endComprobación rápida
¿Cuál es la función de un constructor (new()) en la POO de Lua?
Repaso: constructores
Resumen:
- El constructor valida, inicializa y llama a setmetatable
- Use una tabla de valores predeterminados para gestionar limpiamente los parámetros opcionales
- Use varios métodos de fábrica para distintos escenarios de creación
- Use un constructor de clonación para objetos plantilla
- Use inicialización diferida mediante __index para los campos costosos
- Devuelva nil+err desde el constructor si ocurre un error (por ejemplo, al asignar un recurso)
Preguntas frecuentes
¿La lección «Constructores y new()» es gratis?
Sí — el texto completo de «Constructores y new()» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Lua Academy, actualiza a CoddyKit PRO. El curso de Lua Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Constructores y new()»?
Escriba funciones constructoras que creen e inicialicen instancias. Practicas Lua Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Lua Academy?
No se requiere experiencia previa. Lua Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Constructores y new()»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Lua Academy?
Sí. Cada lección de Lua Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Clases mediante metatablas
- Constructores y new()
- Métodos de instancia y self
- Encapsulación con closures