0Pricing
Lua Academy · Aula

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_1

setmetatable 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))   -- Lua

rawget 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) -- 20

Vá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 Bob

Campo __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, {}) -- ERROR

Verificando 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)                           -- 5

Metatabelas 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-hello

Depuraçã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âmico
  • rawget/rawset ignoram metamétodos
  • Metatabelas compartilhadas permitem um comportamento semelhante ao de classes
  • __metatable protege a metatabela contra inspeção
  • __tostring controla 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

  1. Introdução às metatabelas
  2. __index e __newindex
  3. Metamétodos aritméticos
  4. __tostring e __len
← Voltar para Lua Academy