Lua Tutorial (ix): meta-table and meta-method detailed _lua

Source: Internet
Author: User
Tags anonymous arithmetic lua

The meta table provided in LUA is a personalized behavior that helps LUA data variables complete some of the predefined features, such as the addition of two tables. Assuming both A and B are tables, you can define how expression a+b is evaluated by using the meta table. When Lua tries to add two tables, it checks whether one of them has a meta table and then checks to see if there are __add fields in the meta table, and if so, calls the corresponding values for that field. This value is called the "meta Method", which is used to compute the and of the table.

Each value in Lua has a meta table. Table and UserData can have separate meta tables, while other data type values share the singleton table to which their type belongs. By default, a table does not have a meta table when it is created, such as:

Copy Code code as follows:

t = {}
Print (getmetatable (t))--Output is nil

Here we can use the Setmetatable function to set or modify the meta table of any table.
Copy Code code as follows:

T1 = {}
Setmetatable (T,T1)
ASSERT (getmetatable (t) = = T1)

Any table can be a meta table for any value, and a set of related tables can share a common meta table that describes their common behavior. A table can even be used as its own meta table to describe its unique behavior. In the LUA code, you can only set the table's Metamodel, and to set the meta table for other types of values, you must do so through C code.

1. The meta method of the arithmetic class:

In the following example code, a table is used to represent the collection, and some functions are used to compute the set and intersection of the collection.

Copy Code code as follows:

Set = {}
Local metatable = {}--meta table

--Creates a new collection from the values in the argument list
function Set.new (l)
Local set = {}
--Assigns all Wenzu of the collection created by the method to the MetaTable
Setmetatable (set,metatable)
For _, V. in Ipairs (L) do
SET[V] = True
End
return set
End

--a function that takes two sets of merged sets
function Set.union (a,b)
Local res = set.new{}
For k in pairs (a) do
Res[k] = True
End
For k in pairs (b) do
Res[k] = True
End
return res
End

--a function that takes the intersection of two sets
function Set.intersection (a,b)
Local res = set.new{}
For k in pairs (a) do
RES[K] = B[k]
End
return res
End

function set.tostring (Set)
Local L = {}
For e into pairs (set) do
l[#l + 1] = E
End
Return "{" ... Table.concat (L, ",") ... "}";
End

function Set.print (s)
Print (set.tostring (s))
End

--Finally, the meta method is added to the meta table, so that when two sets created by the Set.new method are
-when added, the multiplication will be redirected to the Set.union method, and the multiply operation will be redirected to the Set.intersection
Metatable.__add = Set.union
Metatable.__mul = Set.intersection

--The following is the test code
S1 = set.new{10,20,30,50}
S2 = set.new{30,1}
S3 = S1 + s2
Set.print (S3)
Set.print (S3 * S1)

--The output result is:
--{1, 30, 10, 50, 20}
--{30, 10, 50, 20}

In the meta table, each arithmetic operator has a corresponding field name, in addition to the above __add (addition) and __mul (multiplication), there are __sub (subtraction), __div (division), __UNM (opposite number), __mod (modulo) and __pow (Power). In addition, you can define the __concat field to describe the behavior of the join operator.

For the example code above, we used the operands of table type on both sides of the arithmetic operator. So if for S1 = S1 + 8,lua is it still working properly? The answer is yes, because LUA locates the meta table, if the first value has a meta table and there is a __add field, LUA will Kewei the method with this word, or else it will see if the second value is a meta table and contains __add fields, and if so, Kewei the method with this word. Finally, if two values do not have a meta method, Lua throws an error. However, for the set.union function in the example above, if executing S1 = S1 + 8 will raise an error because 8 is not a Table object and cannot be based on it to perform the pairs method call. In order to get more accurate error messages, we need to make the following modifications to the Set.union function, such as:

Copy Code code as follows:

function Set.union (a,b)
If Getmetatable (a) ~= metatable or getmetatable (b) ~= metatable
Error ("Attempt to ' add ' a set with a Non-set value")
End
--The following code is the same as the previous example.
... ...
End

2. The meta method of the relational class:

Wenzu can also specify the meaning of the relational operator, which is __eq (equal to), __lt (less than), and __le (less than or equal), and for the other 3 relational operators, LUA does not provide the associated meta method, which can be obtained by inversion of the preceding 3 relational operators. See the following example:

Copy Code code as follows:

Set = {}
Local metatable = {}

function Set.new (l)
Local set = {}
Setmetatable (set,metatable)
For _, V. in Ipairs (L) do
SET[V] = True
End
return set
End

Metatable.__le = function (a,b)
For k in pairs (a) do
If not b[k] then return False end
End
return True
End
Metatable.__lt = function (a,b) return a <= B and not (b <= a) end
Metatable.__eq = function (a,b) return a <= B and B <= a

--Here is the test code:
S1 = set.new{2,4}
S2 = set.new{4,10,2}
Print (S1 <= S2)--true
Print (S1 < S2)--true
Print (S1 >= s1)--true
Print (S1 > S1)--false

Unlike the meta methods of an arithmetic class, the meta method of a relational class cannot be applied to a mixed type.

3. Library-defined meta method:

In addition to the operator-based Metamodel above, LUA also provides a number of meta methods for the framework, such as the print function that always calls ToString to format its output. If the current object has a __tostring method, ToString uses the return value of the Meta method as its own return value, such as:

Copy Code code as follows:

Set = {}
Local metatable = {}

function Set.new (l)
Local set = {}
Setmetatable (set,metatable)
For _, V. in Ipairs (L) do
SET[V] = True
End
return set
End

function set.tostring (Set)
Local L = {}
For e into pairs (set) do
l[#l + 1] = E
End
Return "{" ... Table.concat (L, ",") ... "}";
End

metatable.__tostring = set.tostring


--Here is the test code:
S1 = set.new{4,5,10}
Print (S1)--{5,10,4}

Functions setmetatable and getmetatable also use a field (__metatable) in the meta table to protect the meta table, such as:

Copy Code code as follows:

Mt.__metatable = "Not Your Business"
S1 = set.new{}
Print (getmetatable (S1))--"Not your Business" will be printed at this time
Setmetatable (s1,{})--the error message will be printed: "Cannot change protected metatable"

The output from the code above shows that once the __metatable field is set, Getmetatable returns the value of the field, and Setmetatable throws an error.

4. Table Access Meta Method:

The meta methods of arithmetic classes and relational class operators define behavior for various error conditions, and they do not change the normal behavior of the language. But Lua also provides a way to change the behavior of a table. There are two types of table behaviors you can change: Query table and modify fields that do not exist in the table.

1). __index element Method:

When you access a field that does not exist in the table, the result is nil. If we define the meta method __index for the table, the result of that access will be determined by the method. See the following sample code:

Copy Code code as follows:

Window = {}
Window.prototype = {x = 0, y = 0, Width = +, height = 100}
window.mt = {}--window Wenzu

function Window.new (o)
Setmetatable (O,WINDOW.MT)
Return o
End

--point The window's Meta method __index to an anonymous function
--The Parameters table and key of the anonymous function are taken from the Table.key.
Window.mt.__index = function (Table,key) return Window.prototype[key] End

--Here is the test code:
W = Window.new{x = ten, y = 20}
Print (w.width)--Output 100
Print (W.WIDTH1)--Returns nil because the field does not exist in the Window.prototype variable.

Finally, LUA provides a more concise representation of the __index method, such as: Window.mt.__index = Window.prototype. This method is equivalent to the anonymous function representation method in the previous example. This simple method performs more efficiently than it does, but the method of the function is more extensible.
If you want to disable the __index method when accessing the table, you can do so by using the function Rawget (Table,key). This method does not speed up the access efficiency of the table.

2). __newindex element Method:
Unlike __index, the meta method is used to assign values that do not exist for keys, whereas the former is used for access. When you assign a value to an index that does not exist in a table, the interpreter looks for the __newindex method. If so, call it instead of directly assigning a value. If this meta method points to a Table,lua, the table is assigned a value instead of the original table. In addition, LUA, like __index, also provides a function rawset (Table,key,value) that operates directly from the current table, bypassing the Meta method, and functions like Rawget (Table,key).

3). Table with default values:
By default, the field default value for a table is nil. But we can modify this default value through the meta table, such as:

Copy Code code as follows:

function SetDefault (Table,default)
Local MT = {__index = function () Return default end}
Setmetatable (TABLE,MT)
End
tab = {x = ten, y = 20}
Print (TAB.X,TAB.Z)--10 Nil
SetDefault (tab,0)
Print (TAB.X,TAB.Z)--10 0

4. Track Table access:
both __index and __newindex play a role in the table without the index of the desired access. Therefore, in order to monitor the access status of a table, we can provide an empty table as an agent, then redirect the __index and __newindex meta methods to the original table, see the following code:

Copy Code code as follows:

t = {}--the original table
Local _t = t--keeps private access to an existing table.
t = {}--Create Agent
--Create a meta table
Local MT = {
__index = function (Table,key)
Print (access to element ...). ToString (Key))
Return _t[key]--Returns the field value by accessing the original table
End

__newindex = function (Table,key,value)
Print ("Update of Element" ...) ToString (Key). "To". ToString (value))
_t[key] = value--Updates the original table
End
}
Setmetatable (T,MT)

T[2] = "Hello"
Print (t[2])

--The output result is
--update of element 2 to Hello
--access to Element 2
--hello

5). read-only table:
With the concept of an agent, you can easily implement a read-only table. Just keep track of all updates to the table and raise an error, see the following sample code:

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")
End
}
Setmetatable (PROXY,MT)
Return proxy
End

Days = readonly{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
Print (Days[1])
DAYS[2] = "Noday"

--The output result is:
--[[
Sunday
Lua:d:/test.lua:6: Attempt to update a read-only table
Stack Traceback:
[C]: in function ' ERROR '
D:/test.lua:6: in function <d:/test.lua:5>
D:/test.lua:15:in main Chunk
[C]:?
]]--

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.