🚀 Metamétodos
Personalize como suas tabelas se comportam com operadores e funções!
🚀O que são metamétodos?
Metamétodos são funções "mágicas" que mudam como uma tabela funciona.
Por exemplo: e se você pudesse somar duas tabelas com +?
A "metatabela" é uma tabela especial que contém esses poderes mágicos.
Configurando uma metatabela
local minha_tabela = {} local minha_meta = {} -- Associa a metatabela defina_metatabela(minha_tabela, minha_meta)
__soma: Adição (+)
Permite usar + entre duas tabelas:
local mt = { __soma = função(a, b) retorne {x = a.x + b.x, y = a.y + b.y} fim } local v1 = {x = 10, y = 20} local v2 = {x = 5, y = 5} defina_metatabela(v1, mt) defina_metatabela(v2, mt) local v3 = v1 + v2 exiba(v3.x, v3.y) -- 15, 25
__subtração: Subtração (-)
local mt = { __subtração = função(a, b) retorne {x = a.x - b.x, y = a.y - b.y} fim } local resultado = v1 - v2
__índice: Acessando campos que não existem
É chamado quando você tenta acessar algo que não está na tabela:
local padrao = {cor = "azul", tamanho = "médio"} local mt = { __índice = padrao -- Busca aqui se não encontrar } local camisa = {tamanho = "grande"} defina_metatabela(camisa, mt) exiba(camisa.tamanho) -- "grande" (está na tabela) exiba(camisa.cor) -- "azul" (buscou no padrão!)
O
__índice é a base da herança em Sol! Permite criar "classes" e objetos.
__novo_índice: Controlando atribuições
É chamado quando você tenta criar um campo novo:
local mt = { __novo_índice = função(tabela, chave, valor) exiba("Tentou criar: " .. chave .. " = " .. converta_para_texto(valor)) -- Não faz nada! Campo não é criado. fim } local bloqueada = {} defina_metatabela(bloqueada, mt) bloqueada.novo = 123 -- Mostra mensagem, mas não cria! exiba(bloqueada.novo) -- nulo
__chame: Chamando tabela como função
Permite usar tabela() como se fosse uma função:
local mt = { __chame = função(ego, x) retorne x * ego.fator fim } local multiplicador = {fator = 3} defina_metatabela(multiplicador, mt) exiba(multiplicador(10)) -- 30
__converta_para_texto: Conversão para texto
Controla o que aparece quando você converte para texto:
local mt = { __converta_para_texto = função(p) retorne "Pessoa: " .. p.nome .. " (" .. p.idade .. " anos)" fim } local pessoa = {nome = "Ana", idade = 12} defina_metatabela(pessoa, mt) exiba(pessoa) -- Pessoa: Ana (12 anos)
Tabela completa de metamétodos
Operadores Aritméticos
| Nome | Operação | Descrição |
|---|---|---|
__soma | a + b | Adição |
__subtração | a - b | Subtração |
__multiplicação | a * b | Multiplicação |
__divisão | a / b | Divisão |
__divisão_inteira | a // b | Divisão inteira |
__módulo | a % b | Resto da divisão |
__potência | a ^ b | Exponenciação |
__negação | -a | Negativo unário |
Operadores Binários (Bitwise)
| Nome | Operação | Descrição |
|---|---|---|
__e_binário | a & b | E binário (AND) |
__ou_binário | a | b | OU binário (OR) |
__ou_exclusivo | a ~ b | OU exclusivo (XOR) |
__não_binário | ~a | NÃO binário (complemento) |
__desloque_esquerda | a << b | Deslocamento à esquerda |
__desloque_direita | a >> b | Deslocamento à direita |
Operadores de Comparação
| Nome | Operação | Descrição |
|---|---|---|
__igual | a == b | Igualdade |
__menor_que | a < b | Menor que |
__menor_ou_igual | a <= b | Menor ou igual |
Os operadores
> e >= são derivados de __menor_que e __menor_ou_igual. Não precisam de metamétodos próprios!
Outros Operadores
| Nome | Operação | Descrição |
|---|---|---|
__concatene | a .. b | Concatenação |
__comprimento | #a | Operador de tamanho |
Acesso e Controle
| Nome | Quando É chamado |
|---|---|
__índice | Ler campo inexistente |
__novo_índice | Criar/modificar campo inexistente |
__chame | Chamar tabela como função |
__converta_para_texto | Converter para texto |
Gerenciamento de Memária e Ciclo de Vida
| Nome | Quando É chamado |
|---|---|
__coletor_lixo | Quando objeto é coletado pelo GC (finalizador) |
__feche | Quando variável to-be-closed sai de escopo |
__modo | Define se tabela tem chaves/valores fracos ("k", "v", "kv") |
Exemplo: Operadores Binários
local mt = { __e_binário = função(a, b) retorne a.bits & b.bits fim, __ou_binário = função(a, b) retorne a.bits | b.bits fim } local flags1 = {bits = 0b1010} local flags2 = {bits = 0b1100} defina_metatabela(flags1, mt) defina_metatabela(flags2, mt) exiba(flags1 & flags2) -- 0b1000 (8) exiba(flags1 | flags2) -- 0b1110 (14)
Exemplo: Finalizador (__coletor_lixo)
local mt = { __coletor_lixo = função(ego) exiba("Limpando recurso: " .. ego.nome) -- Fechar arquivo, conexão, etc. fim } local recurso = {nome = "arquivo.txt"} defina_metatabela(recurso, mt) recurso = nulo -- Será coletado eventualmente colete_lixo() -- Força coleta
Exemplo: Variável To-Be-Closed (__feche)
local mt = { __feche = função(ego) exiba("Fechando: " .. ego.nome) fim } função use_recurso() local arquivo a_fechar = defina_metatabela({nome = "dados.txt"}, mt) -- Usa arquivo... -- __feche É chamado automaticamente ao sair do escopo fim use_recurso() -- Exibe: "Fechando: dados.txt"
Exemplo: Tabela Fraca (__modo)
-- Tabela com chaves fracas (não impede coleta das chaves) local cache = {} defina_metatabela(cache, {__modo = "k"}) local chave = {id = 1} cache[chave] = "valor" chave = nulo -- Chave pode ser coletada colete_lixo() -- cache agora está vazio
Exemplo: Criando uma "classe" Vetor
local Vetor = {} Vetor.__índice = Vetor função Vetor.novo(x, y) local ego = {x = x, y = y} defina_metatabela(ego, Vetor) retorne ego fim função Vetor:magnitude() retorne matemática.obtenha_raiz_quadrada(ego.x^2 + ego.y^2) fim função Vetor.__soma(a, b) retorne Vetor.novo(a.x + b.x, a.y + b.y) fim função Vetor.__multiplicação(a, escalar) se obtenha_tipo(escalar) == "número" então retorne Vetor.novo(a.x * escalar, a.y * escalar) fim fim função Vetor.__converta_para_texto(v) retorne "Vetor(" .. v.x .. ", " .. v.y .. ")" fim -- Usando local v1 = Vetor.novo(3, 4) local v2 = Vetor.novo(1, 2) exiba(v1) -- Vetor(3, 4) exiba(v1:magnitude()) -- 5 exiba(v1 + v2) -- Vetor(4, 6) exiba(v1 * 2) -- Vetor(6, 8)
Metamétodos são a chave para criar código flexível e elegante em Sol!
Cuidado: metamétodos podem tornar o código difácil de entender se usados em excesso. Use com moderação!