Métodos de instancia y self
Defina métodos mediante la sintaxis de dos puntos y el parámetro implícito self.
Métodos de instancia y self es una lección gratuita de Lua Academy en CoddyKit. Esta es la lección 3 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.
self es la instancia
Cuando llama a obj:method(), Lua pasa automáticamente obj como primer argumento. Por convención, este parámetro se denomina self. A través de self, el método accede a los datos de la instancia y llama a otros métodos.
local Counter = {}
Counter.__index = Counter
function Counter.new(start)
return setmetatable({value=start or 0, step=1}, Counter)
end
function Counter:increment()
self.value = self.value + self.step
end
function Counter:getValue() return self.value end
local c = Counter.new(10)
c:increment(); c:increment()
print(c:getValue()) -- 12Encadenamiento de métodos
Devuelva self desde los métodos para permitir el encadenamiento: obj:method1():method2():method3(). Cada llamada devuelve el mismo objeto, lo que permite un estilo fluido. Esto funciona mejor con métodos que modifican el estado.
local Builder = {}
Builder.__index = Builder
function Builder.new()
return setmetatable({parts={}},Builder)
end
function Builder:add(s) self.parts[#self.parts+1]=s; return self end
function Builder:addAll(t)
for _,v in ipairs(t) do self.parts[#self.parts+1]=v end
return self
end
function Builder:build() return table.concat(self.parts," ") end
local result = Builder.new()
:add("Hello")
:add("from")
:addAll({"Lua","OOP"})
:build()
print(result) -- Hello from Lua OOPLlamar a otros métodos
Los métodos pueden llamar a otros métodos de la misma instancia mediante self:otherMethod(). Esto fomenta la reutilización del código dentro de una clase. Los auxiliares privados pueden ser funciones locales normales que reciban self explícitamente.
local Stack = {}
Stack.__index = Stack
function Stack.new() return setmetatable({_data={},_size=0},Stack) end
function Stack:push(v) self._size=self._size+1; self._data[self._size]=v end
function Stack:pop()
if self:isEmpty() then return nil end
local v=self._data[self._size]; self._data[self._size]=nil
self._size=self._size-1; return v
end
function Stack:peek()
return not self:isEmpty() and self._data[self._size] or nil
end
function Stack:isEmpty() return self._size==0 end
function Stack:size() return self._size end
local s=Stack.new(); s:push(1);s:push(2);s:push(3)
print(s:pop(),s:peek(),s:size()) -- 3 2 2Advertencia sobre la sobrescritura de métodos
Establecer un campo de instancia con el mismo nombre que un método de clase oculta el método para esa instancia. Normalmente esto es un error; tenga cuidado cuando los nombres de los campos de instancia puedan entrar en conflicto con los nombres de los métodos.
local Dog = {}
Dog.__index = Dog
function Dog.new(n) return setmetatable({name=n},Dog) end
function Dog:speak() print(self.name..": Woof!") end
local d = Dog.new("Rex")
d:speak() -- Rex: Woof!
-- Accidental shadow:
d.speak = "loud" -- now d.speak is a string, not a function
local ok,err = pcall(function() d:speak() end)
print(ok, err) -- false attempt to call a string valueself en las callbacks
Pasar un método como callback hace que se pierda el self implícito. Envuelva el método en una clausura para capturar self.
local Timer = {}
Timer.__index = Timer
function Timer.new(n) return setmetatable({count=n},Timer) end
function Timer:tick()
self.count=self.count-1
print("Ticking, count:", self.count)
end
local t = Timer.new(3)
-- Wrong: loses self
-- local cb = t.tick -- cb(t) works but cb() doesn't
-- Correct: closure captures self
local cb = function() t:tick() end
cb(); cb(); cb() -- Ticking 3 timesMétodos estáticos frente a métodos de instancia
Un método estático se llama sobre la clase, no sobre una instancia. No tiene self (o recibe la clase como self). En Lua no existe una distinción formal; por convención, use . (no :) para los métodos estáticos.
local MathUtils = {}
MathUtils.__index = MathUtils
-- Static method (no instance needed)
function MathUtils.clamp(v, lo, hi)
return math.max(lo, math.min(hi, v))
end
-- Instance method (needs self)
function MathUtils:scale(factor)
self.value = self.value * factor
end
print(MathUtils.clamp(15, 0, 10)) -- 10
local m = setmetatable({value=5},MathUtils)
m:scale(3)
print(m.value) -- 15Métodos mixin
Añada métodos de una tabla mixin a una clase sin herencia formal. Esta es una composición plana: copie o referencie las funciones del mixin en la tabla de la clase.
local Serializable = {}
function Serializable:serialize()
local parts={}
for k,v in pairs(self) do
if type(v)~="function" then
parts[#parts+1]=k.."="..tostring(v)
end
end
return "{"..table.concat(parts,",").."}"
end
local User = {}
User.__index = User
User.serialize = Serializable.serialize -- mixin!
function User.new(n,a) return setmetatable({name=n,age=a},User) end
local u = User.new("Alice",30)
print(u:serialize())Métodos abstractos
Lua no impone los métodos abstractos, pero puede definir un método de la clase base que lance un error y obligue a las subclases a sobrescribirlo. Esta es una convención para indicar «se debe sobrescribir».
local Shape = {}
Shape.__index = Shape
function Shape.new() return setmetatable({},Shape) end
function Shape:area()
error(type(self).." must implement area()",2)
end
function Shape:describe()
print("Shape area:", self:area())
end
local sq={}
setmetatable(sq,{__index=Shape})
function sq:area() return 4*4 end
sq:describe() -- Shape area: 16Tablas de métodos
En las clases con muchos métodos, organícelos en grupos según su funcionalidad. Todos los métodos de una misma tabla comparten la misma búsqueda mediante metatabla, pero puede dividirlos por responsabilidad usando subespacios de nombres.
local Entity = {}
Entity.__index = Entity
Entity.Physics = {}
function Entity.Physics:applyForce(fx,fy)
self.vx=(self.vx or 0)+fx
self.vy=(self.vy or 0)+fy
end
Entity.Render = {}
function Entity.Render:draw()
print(string.format("Draw at (%g,%g)",self.x or 0,self.y or 0))
end
-- Mix into main class
for k,v in pairs(Entity.Physics) do Entity[k]=v end
for k,v in pairs(Entity.Render) do Entity[k]=v end
function Entity.new(x,y) return setmetatable({x=x,y=y},Entity) end
local e=Entity.new(10,20); e:draw(); e:applyForce(5,0); print(e.vx)Delegación frente a herencia
Prefiera la delegación (mantener una referencia) a las cadenas profundas de herencia. Una clase puede delegar en otro objeto en lugar de heredar de él, lo que mantiene bajo el acoplamiento y permite que cada clase se centre en su función.
local Logger = {}
Logger.__index = Logger
function Logger.new(name) return setmetatable({name=name},Logger) end
function Logger:log(msg) print("["..self.name.."] "..msg) end
local Service = {}
Service.__index = Service
function Service.new(name)
return setmetatable({
name=name,
logger=Logger.new(name) -- delegation
},Service)
end
function Service:start()
self.logger:log("starting...") -- delegate logging
print(self.name, "running")
end
Service.new("AuthService"):start()Comprobación rápida
¿Cuál es la diferencia entre obj:method() y obj.method()?
Repaso: métodos de instancia
Resumen:
- Sintaxis de llamada con dos puntos:
obj:method()==obj.method(obj) - Devuelva self para encadenar métodos
- Llame a otros métodos:
self:otherMethod() - Callbacks: envuélvalas en una clausura para conservar self
- Métodos estáticos: use la notación con punto por convención
- Prefiera la delegación a la herencia profunda para obtener flexibilidad
Preguntas frecuentes
¿La lección «Métodos de instancia y self» es gratis?
Sí — el texto completo de «Métodos de instancia y self» 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 «Métodos de instancia y self»?
Defina métodos mediante la sintaxis de dos puntos y el parámetro implícito self. 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 3 de 4.
¿Cuánto tiempo toma la lección «Métodos de instancia y self»?
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