May 12, 2021 Lua
In Lua table we can access the corresponding key to get the value of the value, but we can't operate on both table.
So Lua provides a metatable that allows us to change the behavior of the table, each of which corred with the corresponding meta-method.
For example, using meta-tables, we can define how Lua calculates the addition of two tables.
When Lua tries to add two tables, first check if one of them has a meta-table, then check if there is a field called __add, and if so, call the corresponding value. An __add field, such as "Property", whose corresponding value (often a function or table) is the "meta-method".
There are two important functions to handle metasheets:
The following example shows how to set up a meta-table on a specified table:
mytable = {} -- 普通表 mymetatable = {} -- 元表 setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
The above code can also be written directly in one line:
mytable = setmetatable({},{})
The following is the return object meta-table:
getmetatable(mytable) -- 这回返回mymetatable
The following are commonly used fields in meta-tables:
__newindex: Update: The index does not exist in the table
rawset(t, k, v)
This is the most common key used by metatable.
When you access table through a key, if the key has no value, Lua looks for the key in the table's metalable (assuming there is a __index) key. If __index contains a table, Lua looks for the appropriate key in the table.We can view in interactive mode using the lua command:
$ 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
If __index contains a function, Lua calls that function, and table and keys are passed to the function as arguments.
__index meta-method to see if an element in the table exists, returns a result of nil if it does not exist, or __index returns a result.
mytable = setmetatable({key1 = "value1"}, { __index = function(mytable, key) if key == "key2" then return "metatablevalue" else return nil end end }) print(mytable.key1,mytable.key2)
The output of the instance is:
value1 metatablevalue
Instance resolution:
The mytable table is assigned a value of "value1".
mytable sets up a meta-table, which is __index.
Look for key1 in the mytable table, and if you find it, return the element, and continue if you can't find it.
Look for key2 in the mytable table and, if found, return the element, and continue if it is not found.
Determines whether a metasheet has __index method, __index if the method is a function, the function is called.
We can simply write the above code as:
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } }) print(mytable.key1,mytable.key2)
__newindex method is used to update the table, __index is used to access the table.
When you assign a missing index to a table, the interpreter looks for the __newindex method: if present, the function is called without the assignment.
The following example demonstrates the __newindex the binary method:
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.newkey1)
The output of the above examples is:
value1 nil 新值2 新值1 nil
In the example above, the table sets the meta-method __newindex, which is called without assigning a meta-method when assigning a new index key (mytable.newkey s ."new value 2"). If you assign an index key (key1) that already exists, you are assigned a value without calling the meta-method __newindex.
The following example uses the rawset function to update the table:
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)
The output of the above examples is:
new value "4"
The following example demonstrates a two-table add-up operation:
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用 -- 自定义计算表中最大值函数 table_maxn 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
The output of the above examples is:
1 1 2 2 3 3 4 4 5 5 6 6
__add keys are included in the meta-table and are added together. The list of actions in the table is as follows:
Mode | Describe |
---|---|
__add | The corresponding operator, 'plus'. |
__sub | The corresponding operator '-'. |
__mul | The corresponding operator' . |
__div | Corresponding operator '/'. |
__mod | The corresponding operator '%'. |
__unm | The corresponding operator '-'. |
__concat | Corresponding operator '..'. |
__eq | The corresponding operator' . |
__lt | The corresponding operator, 'lt;'. |
__le | The corresponding operator, 'lt;'. |
__call method is called when Lua calls a value. The following example demonstrates the amount of elements in the calculation table:
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用 -- 自定义计算表中最大值函数 table_maxn 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 -- 定义元方法__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))
The output of the above examples is:
70
__tostring method is used to modify the output behavior of the table. Here are some examples where we customized the output of a table:
mytable = setmetatable({ 10, 20, 30 }, { __tostring = function(mytable) sum = 0 for k, v in pairs(mytable) do sum = sum + v end return "表所有元素的和为 " .. sum end }) print(mytable)
The output of the above examples is:
表所有元素的和为 60
From this article we can see that meta-tables can simplify our code functionality, so understanding Lua's meta-tables allows us to write simpler and better Lua code.