0Pricing
Lua Academy · Aula

Metamétodos aritméticos

Sobrecarregue +, -, *, / e outros operadores com metamétodos.

Metamétodos aritméticos é uma aula grátis de Lua Academy no CoddyKit. Esta é a aula 3 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.

Nomes dos Metamétodos

O Lua define metamétodos para todos os operadores aritméticos. Quando o Lua encontra uma operação aritmética em uma tabela, ele procura o metamétodo correspondente na metatabela da tabela. Se ambos os operandos forem tabelas, o Lua verifica primeiro a metatabela do operando esquerdo.

-- Operator -> Metamethod
-- a + b    -> __add
-- a - b    -> __sub
-- a * b    -> __mul
-- a / b    -> __div
-- a % b    -> __mod
-- a ^ b    -> __pow
-- a // b   -> __idiv
-- -a       -> __unm (unary minus)
-- #a       -> __len
print("Metamethods defined for all Lua operators")

__add para Adição de Vetores

Defina __add em uma tabela de vetor para permitir o uso de +. O metamétodo recebe dois operandos e retorna um novo valor. Ambos os operandos podem ser tabelas, ou um deles pode ser um número — seu metamétodo deve lidar com os dois casos.

local Vec = {}
Vec.__index = Vec

Vec.__add = function(a, b)
  return setmetatable({x=a.x+b.x, y=a.y+b.y}, Vec)
end

Vec.__tostring = function(v)
  return string.format("Vec(%g,%g)", v.x, v.y)
end

function Vec.new(x,y) return setmetatable({x=x,y=y},Vec) end

local v1 = Vec.new(1,2)
local v2 = Vec.new(3,4)
print(tostring(v1 + v2))   -- Vec(4,6)

__sub __mul __div

Defina __sub, __mul e __div de modo semelhante. Para a multiplicação, trate os casos tabela*tabela e tabela*número verificando os tipos dos operandos dentro do metamétodo.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__sub = function(a,b) return V(a.x-b.x, a.y-b.y) end
Vec.__mul = function(a,b)
  if type(a)=="number" then return V(a*b.x, a*b.y)
  elseif type(b)=="number" then return V(a.x*b, a.y*b)
  else return a.x*b.x + a.y*b.y  -- dot product
  end
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end

local v = V(3,4)
print(tostring(v * 2))    -- (6,8)
print(tostring(V(1,0) - V(0,1)))  -- (1,-1)

__unm: Menos Unário

__unm é o metamétodo do menos unário, invocado quando o Lua avalia -obj. Ele recebe o operando (o mesmo valor é passado duas vezes por consistência) e retorna o valor negado.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__unm = function(a) return V(-a.x, -a.y) end
Vec.__tostring = function(v)
  return string.format("(%g,%g)", v.x, v.y)
end

local v = V(3, -4)
print(tostring(-v))    -- (-3,4)
print(tostring(-(-v))) -- (3,-4)

__len para Comprimento Personalizado

__len é chamado quando #obj é avaliado em uma tabela sem uma sequência inteira bruta. Defina-o para retornar um “comprimento” significativo para tipos personalizados, como conjuntos, filas ou contêineres ponderados.

local Bag = {}
Bag.__index = Bag
Bag.__len = function(b) return b._count end

function Bag.new()
  return setmetatable({_count=0, _items={}}, Bag)
end
function Bag:add(item, qty)
  self._items[item] = (self._items[item] or 0) + (qty or 1)
  self._count = self._count + (qty or 1)
end

local bag = Bag.new()
bag:add("apple", 3)
bag:add("banana", 2)
print(#bag)   -- 5

__mod e __pow

__mod trata do operador %; __pow trata de ^. Eles são menos comuns, mas úteis para tipos numéricos personalizados, como inteiros grandes, frações ou objetos de aritmética modular.

local Modular = {}
Modular.__index = Modular
local M = 1000000007

local function mod(n)
  return setmetatable({n = n % M}, Modular)
end

Modular.__add = function(a,b) return mod(a.n + b.n) end
Modular.__mul = function(a,b) return mod(a.n * b.n) end
Modular.__pow = function(a,b)
  local r, base, exp = mod(1), a, b
  while exp > 0 do
    if exp%2==1 then r = r*base end
    base = base*base; exp = math.floor(exp/2)
  end
  return r
end

print((mod(2) ^ 30).n)   -- 73741817 (2^30 mod 1e9+7)

__concat

__concat é acionado pelo operador .. quando pelo menos um operando tem esse metamétodo. Isso permite definir concatenação para tipos personalizados ou criar DSLs encadeáveis.

local Builder = {}
Builder.__index = Builder
Builder.__concat = function(a, b)
  local result = {}
  for _, v in ipairs(a._parts) do result[#result+1] = v end
  if type(b) == "string" then result[#result+1] = b
  else for _, v in ipairs(b._parts) do result[#result+1] = v end end
  return setmetatable({_parts=result}, Builder)
end
Builder.build = function(b) return table.concat(b._parts) end

local function S(s) return setmetatable({_parts={s}},Builder) end
print((S("Hello") .. ", " .. S("World") .. "!"):build())

Metamétodos de Comparação

__eq define == para tabelas (chamado somente quando ambos os operandos têm a mesma metatabela). __lt define <; __le define <=. Observação: ~= usa __eq; > usa __lt com os argumentos invertidos; >= usa __le.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end

Vec.__eq = function(a,b) return a.x==b.x and a.y==b.y end
Vec.__lt = function(a,b)
  return (a.x^2+a.y^2) < (b.x^2+b.y^2)  -- by magnitude
end

print(V(1,2) == V(1,2))  -- true
print(V(1,2) == V(1,3))  -- false
print(V(1,0) < V(2,0))   -- true (1 < 2)

Encadeando Metamétodos

Como os metamétodos retornam valores (geralmente novas tabelas), as operações podem ser encadeadas naturalmente. Cada operador retorna um novo objeto, e o operador seguinte usa esse resultado. Isso permite expressões aritméticas encadeáveis em tipos personalizados.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__add = function(a,b) return V(a.x+b.x,a.y+b.y) end
Vec.__mul = function(a,b)
  if type(b)=="number" then return V(a.x*b,a.y*b) end
  return V(a.x*b.x+a.y*b.y, 0)   -- simplified
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end

local result = V(1,0) + V(0,1) * 3
print(tostring(result))   -- (1,3)

Operações com Tipos Mistos

Quando você escreve vec * 2, o operando esquerdo é a tabela. Quando escreve 2 * vec, o operando esquerdo é um número (sem metamétodo), então o Lua verifica a metatabela do operando direito em busca de __mul. Trate as duas ordens no seu metamétodo.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__tostring = function(v) return "("..v.x..","..v.y..")" end

Vec.__mul = function(a, b)
  if type(a) == "number" then
    return V(a*b.x, a*b.y)   -- scalar * vec
  elseif type(b) == "number" then
    return V(a.x*b, a.y*b)   -- vec * scalar
  end
  return a.x*b.x + a.y*b.y  -- dot product
end

print(tostring(V(1,2) * 3))  -- (3,6)
print(tostring(3 * V(1,2)))  -- (3,6)

Verificação Rápida

Qual metamétodo é acionado por -myTable?

Recapitulação: Metamétodos Aritméticos

Resumo:

  • __add __sub __mul __div __mod __pow __idiv — aritmética binária
  • __unm — menos unário; __len — operador #
  • __concat — operador ..
  • __eq __lt __le — operadores de comparação
  • Trate tipos mistos (número/tabela) dentro dos metamétodos

Perguntas Frequentes

A aula “Metamétodos aritméticos” é grátis?

Sim — o texto completo de “Metamétodos aritméticos” é 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 “Metamétodos aritméticos”?

Sobrecarregue +, -, *, / e outros operadores com metamé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 3 de 4.

Quanto tempo leva a aula “Metamétodos aritméticos”?

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