Introdução às metatabelas
Defina e obtenha metatabelas com setmetatable/getmetatable.
Introdução às 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.
O que é uma metatable?
Uma metatable é uma tabela Lua comum que controla o comportamento de outra tabela. Quando Lua encontra uma operação que não consegue realizar em uma tabela (como uma operação aritmética ou o acesso a uma chave ausente), procura um metamethod correspondente na metatable. Esse é o mecanismo de extensão de Lua para sobrecarga de operadores e programação orientada a objetos.
local t = {}
local mt = {__index = function(_, k) return "default_" .. k end}
setmetatable(t, mt)
print(t.foo) -- default_foo
print(t.bar) -- default_bar
print(t[1]) -- default_1setmetatable e getmetatable
setmetatable(t, mt) define mt como a metatable de t e retorna t. getmetatable(t) retorna a metatable ou nil se não houver nenhuma. Você pode proteger uma metatable contra alterações definindo mt.__metatable = "protected".
local t = {x = 10}
local mt = {}
setmetatable(t, mt)
print(getmetatable(t) == mt) -- true
-- Protect metatable
mt.__metatable = "locked"
print(getmetatable(t)) -- locked
-- setmetatable(t, {}) -- ERROR: cannot change protected metatable__index como tabela
Quando __index é uma tabela, Lua procura a chave ausente nessa tabela. Essa é a base da herança por protótipos de Lua. Se a chave também não estiver em __index, Lua verifica a metatable dela e continua subindo pela cadeia.
local Animal = {sound = "...", legs = 4}
local Dog = setmetatable({sound = "Woof"}, {__index = Animal})
local Cat = setmetatable({sound = "Meow"}, {__index = Animal})
print(Dog.sound) -- Woof (own field)
print(Dog.legs) -- 4 (from Animal)
print(Cat.sound) -- Meow
print(Cat.legs) -- 4__index como função
Quando __index é uma função, Lua a chama com a tabela e a chave ausente. A função pode calcular ou buscar o valor dinamicamente. Retorne nil de __index para indicar "chave não encontrada."
local dynamic = setmetatable({}, {
__index = function(t, k)
if k:sub(1,4) == "get_" then
local field = k:sub(5)
return function(self) return self[field] end
end
return nil
end
})
dynamic.name = "Lua"
local getter = dynamic.get_name
print(getter(dynamic)) -- Luarawget e rawset
rawget(t, k) lê uma chave da tabela sem acionar __index. rawset(t, k, v) define uma chave sem acionar __newindex. Use essas funções para ignorar metamethods quando precisar acessar diretamente uma tabela dentro de um metamethod, evitando recursão infinita.
local logged = setmetatable({}, {
__newindex = function(t, k, v)
print("Setting", k, "=", v)
rawset(t, k, v) -- bypass __newindex
end
})
logged.x = 10 -- Setting x = 10
logged.x = 20 -- no log! key now exists in t
print(logged.x) -- 20Várias Tabelas Compartilhando uma Metatabela
Uma única metatabela pode ser compartilhada por muitas tabelas. É assim que os sistemas de classes do Lua funcionam: todas as instâncias de uma classe compartilham a mesma metatabela, que contém os métodos. Alterações na metatabela afetam todas as instâncias.
local Mt = {
__index = {
greet = function(self)
print("Hello from " .. (self.name or "?"))
end
}
}
local a = setmetatable({name="Alice"}, Mt)
local b = setmetatable({name="Bob"}, Mt)
a:greet() -- Hello from Alice
b:greet() -- Hello from BobCampo __metatable
Definir mt.__metatable com qualquer valor faz com que getmetatable retorne esse valor em vez da metatabela real. Isso impede que os usuários inspecionem ou substituam a metatabela — algo útil para encapsulamento e segurança.
local secret = setmetatable({}, {
__metatable = false, -- hide metatable
__index = {value = 42}
})
print(secret.value) -- 42
print(getmetatable(secret)) -- false (not the real mt)
-- setmetatable(secret, {}) -- ERRORVerificando a Metatabela
Use getmetatable(t) para verificar se um objeto tem uma metatabela específica (para verificação de tipo). Como __metatable pode ocultar a metatabela real, use rawequal ou um campo marcador para verificações confiáveis de instância.
local MyClass = {}
MyClass.__index = MyClass
MyClass.__metatable = MyClass -- use self as marker
function MyClass.new(x)
return setmetatable({x=x}, MyClass)
end
local obj = MyClass.new(5)
print(getmetatable(obj) == MyClass) -- true
print(obj.x) -- 5Metatabelas em Valores que Não São Tabelas
As strings no Lua já têm uma metatabela (o módulo string). É por isso que você pode chamar s:upper() em qualquer string. No Lua puro, não é possível definir metatabelas para strings, números ou booleanos — somente para tabelas e userdata.
local s = "hello"
local mt = getmetatable(s)
-- String metatable has __index = string library
print(mt.__index == string) -- true
-- So all string functions are methods:
print(s:upper()) -- HELLO
print(s:rep(3, "-")) -- hello-hello-helloDepuração com Metatabelas
Você pode adicionar um metamétodo __tostring para controlar como tostring() e print() exibem uma tabela. Isso é extremamente útil para depurar objetos complexos.
local Point = {}
Point.__index = Point
Point.__tostring = function(p)
return string.format("Point(%g, %g)", p.x, p.y)
end
function Point.new(x, y)
return setmetatable({x=x,y=y}, Point)
end
local p = Point.new(3, 4)
print(tostring(p)) -- Point(3, 4)
print(p) -- Point(3, 4) (print calls tostring)Verificação Rápida
O que acontece quando você acessa uma chave não encontrada em uma tabela que tem uma metatabela com __index definido como outra tabela?
Recapitulação: Metatabelas
Resumo:
setmetatable(t, mt)/getmetatable(t)__index: tabela → busca no protótipo; função → despacho dinâmicorawget/rawsetignoram metamétodos- Metatabelas compartilhadas permitem um comportamento semelhante ao de classes
__metatableprotege a metatabela contra inspeção__tostringcontrola a saída de impressão
Perguntas Frequentes
A aula “Introdução às metatabelas” é grátis?
Sim — o texto completo de “Introdução às 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 “Introdução às metatabelas”?
Defina e obtenha metatabelas com setmetatable/getmetatable. 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 “Introdução às 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
- Introdução às metatabelas
- __index e __newindex
- Metamétodos aritméticos
- __tostring e __len