The metatable in Lua is a common table, but it has the following features:
1. Define the behavior of arithmetic operators and relational operators
2. Providing support for the LUA function library
3. Control access to table
Metatables defines operator behavior
MetaTable can be used to define the behavior of arithmetic operators and relational operators. For example, when Lua tries to add to two table, it checks whether there is an existing metatable in the two table sequentially and whether the metatable exists __add domain, and if LUA checks the __add domain, it is called, and the domain is called Metamethod.
Each value in Lua can have a metatable (in Lua 5 only table and UserData can exist metatable). Each table and UserData value has a metatable of its own, while all other types of each value share a metatable that belongs to this type. In the LUA code, the LUA C API can be set to all the metatable of value by invoking setmetatable to set and only set the table's metatable. By default, the string type has its own metatable, while the other types do not:
Copy Code code as follows:
Print (getmetatable (' Hi '))--> table:003c86b8
Print (Getmetatable ())--> Nil
The Metamethod parameters are operands (operands), for example:
Copy Code code as follows:
Local MT = {}
function Mt.__add (A, B)
Return ' table + '. B
End
Local T = {}
Setmetatable (T, MT)
Print (T + 1)
Each arithmetic operator has a corresponding Metamethod:
+ |
__add |
* |
__mul |
- |
__sub |
/ |
__div |
- |
__UNM (for negation) |
% |
__mod |
^ |
__pow |
There is a corresponding metamethod:__concat for the join operator
Similarly, there are corresponding metamethod for relational operators:
The other relational operators are represented in the above three ways:
A ~= B is expressed as not (a = = b)
A > B is represented as B < a
A >= b for B <= a
Unlike arithmetic operators, relational operators are used to compare two value with different metamethod (rather than metatable) with an error, with the exception of comparison operators, and the result of two value comparisons with different Metamethod is false.
Note, however, that a <= B can be converted to not (b < a) in a comparison of integer types, but this condition may not be true if all elements of a type are not sorted properly. For example: Nan (not a number) in a floating-point number represents an undefined value, Nan <= x is always false, and X < NaN is always false.
Support for the Lua function library
The LUA library can define and use Metamethod to perform certain operations, a typical example is the ToString function in the LUA base library (the print function calls this function for output) to check and invoke __tostring Metamethod:
Copy Code code as follows:
Local MT = {}
mt.__tostring = function (t)
Return ' {' ... table.concat (t, ', '). '}'
End
Local T = {1, 2, 3}
Print (t)
Setmetatable (T, MT)
Print (t)
Another example is the setmetatable and getmetatable functions, which define and use the __metatable domain. If you want to set the value of the metatable not be modified, then you can set the __metatable field in the metatable of value, Getmetatable will return this field, and setmetatable will produce an error:
Copy Code code as follows:
Mt.__metatable = "Not Your Business"
Local T = {}
Setmetatable (T, MT)
Print (getmetatable (t))--> not your business
Setmetatable (t, {})
Stdin:1: Cannot change protected metatable
Look at a complete example:
Copy Code code as follows:
Set = {}
Local MT = {}
function Set.new (l)
Local set = {}
--Set metatable for set
Setmetatable (set, MT)
For _, V. in Ipairs (L) does set[v] = True End
return set
End
function Set.union (A, B)
--Check whether a B is all Set
If Getmetatable (a) ~= MT or getmetatable (b) ~= Mt Then
--The second parameter of the error is level
--level specifies how to get the wrong location
--the level value of 1 indicates the location where the error function is called
--A level value of 2 indicates where the error is called where the function calling the error is invoked
Error ("Attempt to ' add ' a set with a Not-set value", 2)
End
Local res = set.new{}
For k in pairs (a) does res[k] = True End
For k in pairs (b) does res[k] = True End
return res
End
function Set.intersection (A, B)
Local res = set.new{}
For k in pairs (a) do
RES[K] = B[k]
End
return res
End
Mt.__add = Set.union
Mt.__mul = Set.intersection
Mt.__tostring = function (s)
Local L = {}
For e in pairs (s) do
l[#l + 1] = E
End
Return ' {' ... table.concat (l, ', '). '}'
End
Mt.__le = function (A, B)
For k in pairs (a) do
If not b[k] then return False end
End
return True
End
Mt.__lt = function (A, B)
Return a <= B and not (b <= a)
End
Mt.__eq = function (A, B)
Return a <= B and B <= a
End
Local S1 = set.new ({1, 2, 3})
Local S2 = set.new ({4, 5, 6})
Print (S1 + s2)
Print (S1 ~= S2)
Control access to table
__index Metamethod
When we access the nonexistent domain of the table, Lua attempts to invoke __index Metamethod. __index Metamethod accepts two parameters table and key:
Copy Code code as follows:
Local MT = {}
Mt.__index = function (table, key)
Print (' Table--'.. tostring (table))
Print (' Key--' ... key ')
End
Local T = {}
Setmetatable (T, MT)
Local v = t.a
__index field can also be a table, Lua will try to access the corresponding domain in __index table:
Copy Code code as follows:
Local MT = {}
Mt.__index = {
A = ' Hello world '
}
Local T = {}
Setmetatable (T, MT)
Print (T.A)--> Hello World
We can easily implement single inheritance through __index (similar to javascrpit through prototype implementation of single inheritance), if __index is a function, you can achieve more complex functions: multiple inheritance, caching and so on. We can access the domain I of table t via Rawget (T, i) without accessing the __index Metamethod, and note that you don't expect to increase access to the table by Rawget (in Lua, the call overhead for functions is much greater than the access to the table. Pins).
__newindex Metamethod
If you assign a value to a nonexistent field in a table, Lua checks for __newindex Metamethod:
1. If __newindex is a function, Lua calls the function instead of assigning it
2. If __newindex is a table,lua, this table will be assigned a value
If __newindex is a function, it can accept three parameter table key value. If you want to ignore the __newindex method to assign values to the table's fields, you can call Rawset (t, K, V)
Combined with __index and __newindex, many functions can be implemented, such as:
1.OOP
2.read-only table
3.Tables with default values
Read-only table
Copy Code code as follows:
function ReadOnly (t)
Local proxy = {}
Local MT = {
__index = T,
__newindex = function (t, K, V)
Error (' Attempt to update a read-only table ', 2)
End
}
Setmetatable (proxy, MT)
Return proxy
End
Days = readonly{' Sun ', ' Mon ', ' Tues ', ' Wed ', ' Thur ', ' Fri ', ' Sat '}
Print (Days[1])
DAYS[2] = ' Noday '--> stdin:1: Attempt to update a read-only table
Sometimes, we need to set a unique key for the table, so we can use this technique:
Copy Code code as follows:
Local key = {}--Unique key
Local T = {}
T[key] = value