English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
En Lua table podemos acceder a la clave correspondiente para obtener el valor, pero no podemos realizar operaciones entre dos tablas.
Por lo tanto, Lua proporciona metatables que nos permiten cambiar el comportamiento de las tablas, cada comportamiento se asocia con un método meta correspondiente.
Por ejemplo, utilizando metatables podemos definir cómo Lua realiza la operación de suma de dos tablas a+b.
Cuando Lua intenta sumar dos tablas, primero verifica si una de ellas tiene un metatable, luego verifica si hay un campo llamado "__add", si encuentra uno, llama al valor correspondiente. Los campos "__add" y otros campos inmediatos, cuyos valores (que suelen ser funciones o tablas) son "métodos meta".
Hay dos funciones muy importantes para manejar metatables:
setmetatable(table, metatable): Establecer el metatable de una tabla específica, si el metatable contiene la clave __metatable, setmetatable fallará.
getmetatable(table): Devuelve el metatable del objeto.
A continuación se muestra un ejemplo de cómo establecer un metatable para una tabla específica:
mytable = {} -- Tabla común mymetatable = {} -- Metatable setmetatable(mytable, mymetatable) -- Establecer mymetatable como el metatable de mytable
El código anterior también se puede escribir en una línea:
mytable = setmetatable({}, {})
A continuación se muestra el objeto metatable devuelto:
getmetatable(mytable) -- Esto devolverá mymetatable
Esta es la clave más utilizada en el metatable.
Cuando accedemos a una tabla mediante una clave, si esa clave no tiene valor, Lua buscará la clave __index en el metatable de la tabla (asumiendo que hay un metatable). Si __index contiene una tabla, Lua buscará la clave correspondiente en la tabla.
Podemos usar el comando lua para entrar en modo interactivo y ver:
$ 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
Si __index contiene una función, Lua la llamará y la tabla y la clave se pasarán como parámetros a la función.
__index método verificar si el elemento existe en la tabla, si no existe, el resultado es nil; si existe, el resultado se devuelve por __index.
mytable = setmetatable({key1 = "valor1"}, { __index = function(mytable, key) if key == "key2" return "metatablevalue" else return nil end end ) print(mytable.key1,mytable.key2)
El resultado de la salida del ejemplo es:
value1 metatablevalue
Ejemplo de análisis:
Asignar el valor de mytable {key1 = "value1"}.
mytable configuró la metatable, el método de metaprograma es __index.
Buscar key en mytable1,si se encuentra, devolver el elemento, si no se encuentra, continuar.
Buscar key en mytable2,si se encuentra, devolver metatablevalue, si no se encuentra, continuar.
Si el método __index es una función, llamar a esta función.
Verificar si la metatable tiene el método __index en el método de metaprograma2"parámetro de clave (mytable.key2ya configurado),si se ingresa "key2" Parámetro de retorno "metatablevalue", de lo contrario, devolver el valor asociado a la clave de mytable.
Podemos simplificar el código anterior de la siguiente manera:
mytable = setmetatable({key1 = "valor1"}2 = "metatablevalue"} print(mytable.key1,mytable.key2)
Resumen
Las reglas de Lua para buscar elementos en una tabla, es en realidad lo siguiente 3 etapas:
1.Buscar en la tabla, si se encuentra, devolver el elemento, si no se encuentra, continuar
2.Verificar si la tabla tiene una metatable, si no tiene metatable, se devuelve nil, si tiene metatable, continuar.
3.Verificar si la metatable tiene el método __index, si __index es nil, se devuelve nil; si __index es una tabla, se repite 1、2、3;si el método __index es una función, se devuelve el valor de retorno de esta función.
Este contenido proviene del autor Huanzi: https://blog.csdn.net/xocoder/article/details/9028347
El método __newindex se utiliza para actualizar tablas, mientras que __index se utiliza para acceder a tablas.
Cuando se asigna un valor a un índice faltante de una tabla, el intérprete busca el método __newindex: si existe, llama a esta función sin realizar la operación de asignación.
El siguiente ejemplo muestra la aplicación del método __newindex:
mymetatable = {} mytable = setmetatable({key1 = "valor1"} print(mytable.key1) mytable.newkey = "nuevo valor"2" print(mytable.newkey,mymetatable.newkey) mytable.key1 = "nuevo valor"1" print(mytable.key1,mymetatable.key1)
El resultado de ejecutar el ejemplo anterior es:
value1 nil nuevo valor2 nuevo valor1 nil
En el ejemplo anterior, la tabla ha establecido el método meta __newindex, al asignar un nuevo índice de clave (mytable.newkey = "nuevo valor2si se llama a un método meta, sin realizar la asignación. Y si se asigna a una clave de índice existente (key1) se realizará la asignación, sin llamar al método meta __newindex.
A continuación se muestra un ejemplo que utiliza la función rawset para actualizar la tabla:
mytable = setmetatable({key1 = "valor1"}, { __newindex = function(mytable, key, value) rawset(mytable, key, "\""..value.."\"") end ) mytable.key1 = "nuevo valor" mytable.key2 = 4 print(mytable.key1,mytable.key2)
El resultado de ejecutar el ejemplo anterior es:
nuevo valor"4"
A continuación se muestra un ejemplo que ilustra la operación de suma de dos tablas:
-- Calcular el valor máximo de la tabla, table.maxn en Lua5.2Esta versión ya no se puede usar -- Función personalizada de cálculo del valor clave máximo de la tabla table_maxn, es decir, calcular el número de elementos de la tabla 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 -- operación de suma de dos tablas 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
El resultado de ejecutar el ejemplo anterior es:
1 1 2 2 3 3 4 4 5 5 6 6
__add clave contiene en la tabla meta y realiza la operación de suma. La lista de operaciones correspondientes en la tabla es la siguiente: (Atención:__es dos guiones bajos)
patrón | descripción |
---|---|
__add | corresponde al operador '+'. |
__sub | corresponde al operador '-'. |
__mul | corresponde al operador '*'. |
__div | corresponde al operador '/'. |
__mod | corresponde al operador '%'. |
__unm | corresponde al operador '-'. |
__concat | corresponde al operador '..'. |
__eq | corresponde al operador '=='. |
__lt | corresponde al operador '<'. |
__le | corresponde al operador '<='. |
__call método meta en Lua se llama a un valor. A continuación se muestra un ejemplo que ilustra la suma de elementos de una tabla:
-- Calcular el valor máximo de la tabla, table.maxn en Lua5.2Esta versión ya no se puede usar -- Función personalizada de cálculo del valor clave máximo de la tabla table_maxn, es decir, calcular el número de elementos de la tabla 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 el 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))
El resultado de ejecutar el ejemplo anterior es:
70
El método meta __tostring se utiliza para modificar el comportamiento de salida de la tabla. A continuación, se muestra un ejemplo en el que personalizamos el contenido de salida de la tabla:
mytable = setmetatable({ 10, 20, 30 }, { __tostring = function(mytable) sum = 0 for k, v in pairs(mytable) do sum = sum + v end return "La suma de todos los elementos de la tabla es" .. sum end ) print(mytable)
El resultado de ejecutar el ejemplo anterior es:
La suma de todos los elementos de la tabla es 60
Podemos saber de este artículo que los metatables pueden simplificar nuestras funciones de código, por lo que entender los metatables de Lua nos permitirá escribir código Lua más simple y excelente.