English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Metatable do Lua

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

__index método meta

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

__newindex método meta

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 元方法

__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

Método meta __tostring

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.