O Metamétodo __newindex
Parte da seção Logic & Flow do Journey de Lua da Coddy — lição 19 de 54.
Você aprendeu como __index controla o que acontece quando você tenta ler uma chave que não existe em uma tabela. Agora você descobrirá sua contraparte: __newindex, que controla o que acontece quando você tenta adicionar ou modificar um par chave-valor.
O metamétodo __newindex é acionado sempre que você tenta atribuir um valor a uma chave que não existe atualmente na tabela. Isso lhe dá o poder de interceptar e controlar modificações antes que elas ocorram.
Aqui está um exemplo simples que impede que novas chaves sejam adicionadas a uma tabela:
local readOnly = {}
local meta = {
__newindex = function(table, key, value)
print("Cannot add key: " .. key)
end
}
setmetatable(readOnly, meta)
readOnly.name = "Alice" -- Saída: Cannot add key: name
print(readOnly.name) -- Saída: nilQuando você tenta definir readOnly.name = "Alice", o Lua vê que name não existe na tabela. Em vez de adicioná-lo, o Lua chama a função __newindex com três argumentos: a própria tabela, a chave que está sendo definida e o valor que está sendo atribuído.
Neste exemplo, a função simplesmente imprime uma mensagem e não armazena nada de fato.
Você também pode usar __newindex para validar dados antes de permiti-los em sua tabela:
local player = {}
local meta = {
__newindex = function(t, key, value)
if key == "health" and type(value) ~= "number" then
print("Health must be a number!")
else
rawset(t, key, value)
end
end
}
setmetatable(player, meta)
player.health = "high" -- Saída: Health must be a number!
player.health = 100 -- PermitidoObserve o uso de rawset() no segundo exemplo. Esta função ignora a metatable e define o valor diretamente na tabela.
Sem isso, definir o valor dispararia __newindex novamente, criando um loop infinito.
Desafio
FácilEscreva uma função createValidatedTable que recebe key e value e retorna uma tabela que aceita apenas valores do tipo string para novas chaves.
Crie uma tabela vazia e anexe um metatable com __newindex que valida o tipo do valor. Se alguém tentar adicionar um valor que não seja string, use rawset() para armazenar a string "invalid" em seu lugar. Para valores do tipo string, armazene-os normalmente usando rawset().
Lógica:
- Crie uma tabela vazia
- Crie um metatable com
__newindexque recebe a tabela, a chave e o valor - Dentro de
__newindex, verifique se o valor é uma string usandotype(value) == "string" - Se for uma string, use
rawset(t, key, value)para armazená-la - Se não for uma string, use
rawset(t, key, "invalid")para armazenar"invalid"em seu lugar - Anexe o metatable à tabela usando
setmetatable() - Use
rawset()para adicionar o par chave-valor inicial à tabela (ignorando o metatable) - Retorne a tabela
Parâmetros:
key(string): A chave inicial para adicionar à tabelavalue(string): O valor inicial para adicionar à tabela
Retorna: Uma tabela com validação que aceita apenas valores string, contendo o par chave-valor inicial (table)
Folha de consulta
O metamétodo __newindex é acionado quando você tenta atribuir um valor a uma chave que não existe em uma tabela, permitindo interceptar e controlar modificações.
Exemplo básico impedindo novas chaves:
local readOnly = {}
local meta = {
__newindex = function(table, key, value)
print("Cannot add key: " .. key)
end
}
setmetatable(readOnly, meta)
readOnly.name = "Alice" -- Saída: Cannot add key: name
print(readOnly.name) -- Saída: nilA função __newindex recebe três argumentos: a própria tabela, a chave que está sendo definida e o valor que está sendo atribuído.
Validando dados com __newindex:
local player = {}
local meta = {
__newindex = function(t, key, value)
if key == "health" and type(value) ~= "number" then
print("Health must be a number!")
else
rawset(t, key, value)
end
end
}
setmetatable(player, meta)
player.health = "high" -- Saída: Health must be a number!
player.health = 100 -- PermitidoUse rawset(t, key, value) para ignorar a metatabela e definir valores diretamente na tabela. Isso evita loops infinitos ao definir valores dentro de __newindex.
Experimente você mesmo
function createValidatedTable(key, value)
-- Escreva o código aqui
end
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Logic & Flow
1Iteração Avançada de Tabelas
Iterando com pairs()Iterando com ipairs()pairs() vs. ipairs()Revisão - Ficha de Personagem4Introdução às Metatabelas
O que é uma Metatabela?setmetatable & getmetatableO Metamétodo __indexO Metamétodo __newindexO Metamétodo __tostringMetamétodos Aritméticos Parte 1Metamétodos Aritméticos Parte 2Recapitulação - Tabela Somente Leitura2Mais Funções da Biblioteca Table
table.concat()Construção de tabelas e unpack()table.sort()Ordenação personalizada com funçõesRecapitulação - Placar de recordes