English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Em tabelas do Lua, podemos acessar a chave correspondente para obter o valor, mas não podemos operar duas tabelas.
Portanto, o Lua oferece metatabelas (metatable), permitindo que alteremos o comportamento das tabelas, cada comportamento associado a um método meta correspondente.
Por exemplo, usando a metatabela, podemos definir como o Lua calcula a soma de duas tabelas a+b.
Quando o Lua tenta somar dois tabelas, ele primeiro verifica se uma das tabelas tem uma metatabela, e em seguida verifica se há um campo chamado "__add", se encontrar, chama o valor correspondente. Campos como "__add" são chamados de campos instantâneos, e os valores correspondentes (frequentemente uma função ou tabela) são chamados de "métodos meta".
Existem duas funções muito importantes para lidar com metatabelas:
setmetatable(table, metatabela): Define uma metatabela para a tabela específica, se a metatabela tiver a chave __metatable, setmetatable falhará.
getmetatable(table): Retorna a tabela meta do objeto.
O exemplo a seguir demonstra como definir uma metatabela para uma tabela específica:
mytable = {} -- Tabela comum mymetatable = {} -- Metatabela setmetatable(mytable, mymetatable) -- Definir mymetatable como a metatabela de mytable
O código acima também pode ser escrito em uma linha:
mytable = setmetatable({}, {})
A seguir está a tabela meta retornada:
getmetatable(mytable) -- Isso retorna mymetatable
Essa é a chave mais usada na metatabela.
Quando você acessa uma tabela por meio de uma chave, se essa chave não tiver valor, o Lua procurará a metatabela da tabela (supondo que exista uma metatabela) na chave __index.
Podemos usar o comando lua para entrar no modo interativo e verificar:
$ lua Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio > other = { foo = 3 } > t = setmetatable({}, { __index = other }) > t.foo 3 > t.bar nil
Se __index contiver uma função, o Lua chama essa função, passando a tabela e a chave como argumentos para a função.
__index método meta verifica se o elemento existe na tabela, se não existir, retorna nil; se existir, o __index retorna o resultado.
mytable = setmetatable({key1 = "value1"}, { __index = function(mytable, key) if key == "key2" then return "metatablevalue" else return nil end end ) print(mytable.key1,mytable.key2)
O resultado de saída do exemplo é:
value1 metatablevalue
Exemplo de análise:
Atribua o valor ao mytable {key1 = "value1"}.
mytable configurou a tabela meta, o método meta é __index.
Procure por key no mytable1e, se encontrar, retorne o elemento; se não encontrar, continue.
Procure por key no mytable2e, se encontrar, retorne metatablevalue, caso contrário, continue.
Verifique se a tabela meta possui o método __index. Se __index for uma função, chame essa função.
verifique o método meta se foi passado "key2" chave do parâmetro (mytable.key2já configurado), se passado "key2" Parâmetro de retorno "metatablevalue", caso contrário, retorne o valor correspondente à chave do mytable.
Podemos simplificar o código acima da seguinte forma:
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } }) print(mytable.key1,mytable.key2)
Resumo
As regras do Lua para encontrar elementos em uma tabela são, na verdade, como follows 3 passos:
1.Procure na tabela, se encontrar, retorne o elemento; se não encontrar, continue.
2.Verifique se a tabela possui uma tabela meta. Se não houver tabela meta, retorne nil; se houver, continue.
3.Verifique se a tabela meta possui o método __index. Se __index for nil, retorne nil; se __index for uma tabela, repita 1,2,3Se o método __index é uma função, retorna o valor retornado pela função.
Este conteúdo é extraído do autor Huanzi: https://blog.csdn.net/xocoder/article/details/9028347
O método meta __newindex é usado para atualizar tabelas, enquanto __index é usado para acessar tabelas.
Quando você atribui um valor a um índice ausente de uma tabela, o interpretador busca o método meta __newindex: se existir, ele chama essa função sem realizar a operação de atribuição.
A seguir, um exemplo demonstra o uso do método meta __newindex:
mymetatable = {} mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable }) print(mytable.key1) mytable.newkey = "新值"2" print(mytable.newkey,mymetatable.newkey) mytable.key1 = "新值1" print(mytable.key1,mymetatable.key1)
O resultado da execução do exemplo acima é:
value1 nil 新值2 新值1 nil
以上示例中表设置了元方法 __newindex,在对新索引键(newkey)赋值时(mytable.newkey = "新值2"),会调用元方法,而不进行赋值。而如果对已存在的索引键(key1),则会进行赋值,而不调用元方法 __newindex。
以下示例使用了 rawset 函数来更新表:
mytable = setmetatable({key1 = "value1"}, { __newindex = function(mytable, key, value) rawset(mytable, key, "\""..value.."\"") end ) mytable.key1 = "new value" mytable.key2 = 4 print(mytable.key1,mytable.key2)
O resultado da execução do exemplo acima é:
new value "4"
以下示例演示了两表相加操作:
-- Calcular o maior valor da tabela, table.maxn no Lua5.2A versão acima já não pode ser usada -- Função personalizada de cálculo do maior valor da tabela, table.maxn, que calcula o número de elementos da tabela function table_maxn(t) local mn = 0 for k, v in pairs(t) do if mn < k then mn = k end end return mn end -- 两表相加操作 mytable = setmetatable({ 1, 2, 3 }, { __add = function(mytable, newtable) for i = 1, table_maxn(newtable) do table.insert(mytable, table_maxn(mytable)+1,newtable[i]) end return mytable end ) secondtable = {4,5,6} mytable = mytable + secondtable for k,v in ipairs(mytable) do print(k,v) end
O resultado da execução do exemplo acima é:
1 1 2 2 3 3 4 4 5 5 6 6
__add 键包含在元表中,并进行相加操作。 表中对应的操作列表如下:(注意:__是两个下划线)
模式 | 描述 |
---|---|
__add | 对应的运算符 '".+'. |
__sub | 对应的运算符 '".-'. |
__mul | 对应的运算符 '".*'. |
__div | 对应的运算符 '"./'. |
__mod | 对应的运算符 '%'. |
__unm | 对应的运算符 '".-'. |
__concat | 对应的运算符 '..'. |
__eq | 对应的运算符 '=='. |
__lt | 对应的运算符 '<'. |
__le | 对应的运算符 '<='. |
__call 元方法在 Lua 调用一个值时调用。以下示例演示了计算表中元素的和:
-- Calcular o maior valor da tabela, table.maxn no Lua5.2A versão acima já não pode ser usada -- Função personalizada de cálculo do maior valor da tabela, table.maxn, que calcula o número de elementos da tabela function table_maxn(t) local mn = 0 for k, v in pairs(t) do if mn < k then mn = k end end return mn end -- Definir o método meta __call mytable = setmetatable({10}, { __call = function(mytable, newtable) sum = 0 for i = 1, table_maxn(mytable) do sum = sum + mytable[i] end for i = 1, table_maxn(newtable) do sum = sum + newtable[i] end return sum end ) newtable = {10,20,30} print(mytable(newtable))
O resultado da execução do exemplo acima é:
70
O método meta __tostring é usado para modificar o comportamento de saída da tabela. No exemplo a seguir, personalizamos o conteúdo de saída da tabela:
mytable = setmetatable({ 10, 20, 30 }, { __tostring = function(mytable) sum = 0 for k, v in pairs(mytable) do sum = sum + v end return "A soma de todos os elementos da tabela é" .. sum end ) print(mytable)
O resultado da execução do exemplo acima é:
A soma de todos os elementos da tabela é 60
Podemos saber deste artigo que a metatable pode simplificar muito as funcionalidades do nosso código, então entender a metatable do Lua nos permitirá escrever código Lua mais simples e excelente.