Classes com metatabelas
Simule classes usando tabelas e __index para localizar métodos.
Classes com metatabelas é uma aula grátis de Lua Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Lua Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Lua Academy inclui 4 aulas no total.
Padrão de tabela de classe
Em Lua, uma “classe” é apenas uma tabela que armazena métodos. As instâncias são tabelas cujo metatable tem __index apontando para a tabela da classe. Isso torna todos os métodos acessíveis nas instâncias por meio da cadeia de busca.
local Animal = {}
Animal.__index = Animal
function Animal.new(name, sound)
return setmetatable({name=name, sound=sound}, Animal)
end
function Animal:speak()
print(self.name .. " says " .. self.sound)
end
local dog = Animal.new("Rex","Woof")
dog:speak() -- Rex says Woof__index aponta para a classe
Definir ClassName.__index = ClassName significa “procurar chaves ausentes na tabela da classe”. Quando um método da instância é chamado, Lua não o encontra na instância, verifica o metatable (__index), encontra a classe e procura o método nela.
local Point = {}
Point.__index = Point
Point.type = "2D Point"
function Point.new(x,y)
return setmetatable({x=x,y=y}, Point)
end
function Point:magnitude()
return math.sqrt(self.x^2 + self.y^2)
end
local p = Point.new(3,4)
print(p:magnitude()) -- 5.0
print(p.type) -- 2D Point (from class)Padrão de construtor
A função new() é o construtor: ela cria uma tabela com dados da instância e a retorna envolvida em um metatable que aponta para a classe. Essa é a maneira padrão de criar objetos em Lua.
local Circle = {}
Circle.__index = Circle
function Circle.new(cx, cy, radius)
assert(radius > 0, "radius must be positive")
return setmetatable({cx=cx, cy=cy, r=radius}, Circle)
end
function Circle:area()
return math.pi * self.r^2
end
function Circle:perimeter()
return 2 * math.pi * self.r
end
local c = Circle.new(0, 0, 5)
print(string.format("Area: %.2f", c:area()))Sintaxe de método versus função
obj:method() é uma forma abreviada de obj.method(obj). Defina métodos com a sintaxe de dois-pontos (function Cls:method()) para obter um self implícito. Chame-os com dois-pontos para passar a instância. Misturar ponto e dois-pontos causa erros sutis.
local Dog = {}
Dog.__index = Dog
-- Define with colon: self is implicit
function Dog:bark(times)
for i = 1, (times or 1) do
print(self.name .. ": Woof!")
end
end
function Dog.new(name)
return setmetatable({name=name}, Dog)
end
local d = Dog.new("Buddy")
d:bark(2) -- Buddy: Woof! (x2)
-- Dog.bark(d,1) -- same thing, explicit selfCampos no nível da classe versus da instância
Os campos da tabela da classe são compartilhados por todas as instâncias (variáveis da classe). Os campos da tabela da instância são específicos de cada instância. Uma instância pode ocultar um campo da classe criando seu próprio campo com o mesmo nome.
local Entity = {}
Entity.__index = Entity
Entity.count = 0 -- class-level counter
function Entity.new(name)
Entity.count = Entity.count + 1
return setmetatable({name=name, id=Entity.count}, Entity)
end
local a = Entity.new("alpha")
local b = Entity.new("beta")
local c = Entity.new("gamma")
print(Entity.count) -- 3
print(a.id, b.id, c.id) -- 1 2 3tostring para classes
Adicione __tostring à tabela da classe para obter uma saída de impressão legível. Como o metatable da instância é a classe, e a classe tem __tostring, todas as instâncias o usarão automaticamente.
local Vec2 = {}
Vec2.__index = Vec2
Vec2.__tostring = function(v)
return string.format("Vec2(%g, %g)", v.x, v.y)
end
function Vec2.new(x,y)
return setmetatable({x=x,y=y}, Vec2)
end
function Vec2.__add(a, b)
return Vec2.new(a.x+b.x, a.y+b.y)
end
local v1 = Vec2.new(1,2)
local v2 = Vec2.new(3,4)
print(v1+v2) -- Vec2(4, 6)Verificando o tipo da instância
Verifique se um objeto é uma instância de uma classe comparando seu metatable com a tabela da classe. Esse é o equivalente de instanceof em Lua.
local Dog = {}
Dog.__index = Dog
function Dog.new(name)
return setmetatable({name=name}, Dog)
end
local function isDog(obj)
return getmetatable(obj) == Dog
end
local d = Dog.new("Rex")
local t = {}
print(isDog(d)) -- true
print(isDog(t)) -- falseMétodos privados
Métodos privados são funções locais no arquivo do módulo. Eles não podem ser chamados de fora, mas ficam acessíveis dentro dos métodos públicos do módulo como valores externos.
local Account = {}
Account.__index = Account
-- Private helper
local function validate(amount)
return type(amount)=="number" and amount > 0
end
function Account.new(balance)
return setmetatable({balance=balance or 0}, Account)
end
function Account:deposit(amount)
assert(validate(amount), "invalid amount")
self.balance = self.balance + amount
end
function Account:getBalance() return self.balance endComparação de classes
Sobrecarregue __eq e __lt para personalizar a igualdade e a ordenação. Lua só chama __eq para tabelas quando os dois operandos compartilham o mesmo metatable.
local Temp = {}
Temp.__index = Temp
Temp.__eq = function(a,b) return a.celsius == b.celsius end
Temp.__lt = function(a,b) return a.celsius < b.celsius end
Temp.__tostring = function(t)
return t.celsius.."°C"
end
function Temp.new(c)
return setmetatable({celsius=c}, Temp)
end
local t1 = Temp.new(100)
local t2 = Temp.new(0)
print(t1 == Temp.new(100)) -- true
print(t2 < t1) -- trueVárias classes
Cada classe é uma tabela independente com seu próprio metatable. Objetos de classes diferentes têm metatables diferentes. Essa é a base de um sistema de POO com várias classes em Lua.
local Cat = {}
Cat.__index = Cat
function Cat.new(name) return setmetatable({name=name,lives=9},Cat) end
function Cat:loseLife() self.lives=self.lives-1; return self.lives end
local Dog2 = {}
Dog2.__index = Dog2
function Dog2.new(name) return setmetatable({name=name,tricks={}},Dog2) end
function Dog2:learn(t) self.tricks[#self.tricks+1]=t end
local c = Cat.new("Whiskers")
local d = Dog2.new("Buddy")
d:learn("sit"); d:learn("stay")
print(c:loseLife(), #d.tricks) -- 8 2Verificação rápida
Por que definimos ClassName.__index = ClassName?
Recapitulação: classes por meio de metatables
Resumo:
- Classe = tabela +
__index = self - Construtor:
function Cls.new(...) return setmetatable({}, Cls) end - Métodos: definidos na tabela da classe e chamados com a sintaxe de dois-pontos
- Campos da classe versus da instância: campos da classe compartilhados, campos da instância específicos de cada objeto
- Verificação de tipo:
getmetatable(obj) == Cls
Perguntas Frequentes
A aula “Classes com metatabelas” é grátis?
Sim — o texto completo de “Classes com metatabelas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Lua Academy, atualize para CoddyKit PRO. O curso de Lua Academy inclui 4 aulas no total.
O que vou aprender em “Classes com metatabelas”?
Simule classes usando tabelas e __index para localizar métodos. Você pratica Lua Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Lua Academy?
Nenhuma experiência prévia é necessária. Lua Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Classes com metatabelas”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Lua Academy?
Sim. Cada aula de Lua Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Classes com metatabelas
- Construtores e new()
- Métodos de instância e self
- Encapsulamento com fechamentos