MetaTable and Metamethod

Source: Internet
Author: User
Tags lua set set

What do metatable and Metamethod use for? They can make the expression "A + B" of tables A and b make sense, where metatable makes it possible to manipulate two unrelated tables A and B, and the specific behavior of the operation, such as "+", is specifically defined by Metamethod.

MetaTable and Metamethod Most places are translated into "meta-tables" and "meta-functions", which is a literal translation, rather than intuitive. Based on the use of metatable, I tend to translate metatable into related tables , metamethod into associative functions . By setting metatable for two table, you can make two table connections and then perform some operations on two table, defined by Metamethod . In the following example, after setting the associated table Mt to table T1 and T2 and defining the associated function __add in MT, you can add a "+" to the two tables.

T1 = {1, 2, 3}t2 = {4,5,6,7,8}mt = {}mt.__add = function (A, b)    local ret = 0    for _, V-Pairs (a) do        ret = RET + V    End    for _, V in pairs (b) do        ret = ret + v    end    return retendsetmetatable (T1, MT) setmetatable (T2 , MT) Print (t1 + T2)

From the code above you can see that the associated table is a table, and the association function is a function. When the expression "T1+t2" is encountered, Lua first looks up their association table, and after finding the associated table MT, the associated function __add corresponding to the add operation is found in MT, __add T1 and T2 as parameters to execute the function, and finally returns the result.

The following is an example of using an association table to manipulate a collection (a collection implemented by a table) that defines the set, intersection, compare, and so on of a collection:

Set = {}--is specifically used as a metatable, defined inside the set to avoid affecting the outer namespace set.mt = {}--conversion to stringset.tostring = function (set) local s = "{" L ocal Sep = "" For E in Pairs (set) does S = S.. Sep: E Sep = "," End return S: "}"     end--Print Set.print = function (s) print (set.tostring (s)) endset.mt.__tostring = set.tostring--Create a new collection set.new = function (t) Local set = {}setmetatable (set, SET.MT)--Specifies the metatable of the created collection    For _, L in Ipairs (t) do set[l] = True End return setend--and set set.union = function (A, b) local res = set.new{} For k in pairs (a) does res[k] = True end for k in pairs (b) do res[k] = True End return resend--add MetaTable function to __add (met Amethod), when Lua attempts to add two sets, this function is called, with two tables added as parameters Set.mt.__add = set.union--intersection set.intersection = function (A, b) local res = Se t.new{} for K in pairs (a) do res[k] = B[k] End return resend--Define collection multiply operation for intersection Set.mt.__mul = set.intersection- -Define the "<=" Operation first, and then define "<" and "=" Set.mt.__le = function (A, b) for K in pairs (a) does if not b[k] and then return false End end return trueend--less than set.mt.__lt = function (A, b) return a<=b and not (b <= a) end--equals set.mt.__eq = Fun Ction (A, B) return a <= B and b <= aend--test S1 = set.new{1, 2, 3}s2 = Set.new{10, C, +, +, 50}print (getmetatabl E (S1)) print (getmetatable (s2)) s3 = S1 + S2--equivalent to set.union (S1, S2) print (S3) print (s3 * s2) print (S1 <= S3) Print (S1 = S3) ) Print (S1 < S3) Print (S1 >= S3) print (S1 > S3) --protection, getmetatable will return the value of this field, and setmettable will be error set.mt.__metatable = "Not Your Business"Print (getmetatable (S1)) setmetatable (S1, {})

When Lua tries to add two tables, he checks two tables for a table with metatable and checks if MetaTable has a __add domain. If found, call this __add function (the so-called Metamethod) to calculate the result. When two tables have different metatable, whose is it? Lua chooses the Metamethod principle:

(1) If the first parameter has a metatable with a __add field ,Lua uses it as a metamethod, regardless of the second parameter;

(2) Otherwise, the second parameter exists with the __add domain Metatable,lua use it as a metamethod;

(3) Otherwise, error.

Common Metamethod defined in Lua are as follows:

Metamethod of arithmetic operators:__add (Add operation),__mul (multiply),__sub (minus ),__div (except ),__unm (negative ),__pow (Power ),__concat (defines the connection behavior).

Metamethod of relational operators: __eq (equals),__lt (less than),__le (less than equals), other relational operations are automatically converted to these three basic operations.

Library-defined Metamethod: __tostring (the behavior of the ToString function), __metatable (Behavior on table getmetatable and setmetatable).

Note: __metatable is not a function, but a variable. Suppose you want to protect your collection so that its users can neither see nor modify metatables. If you set the __metatable value for metatable,getmetatable will return the value of the field, and the call will be setmetatable with an error:

Note: an equality comparison never throws an error, and if two objects have different metamethod, the result of the comparison is false and may not even call Metamethod. This also mimics the public behavior of LUA, because Lua always considers strings and numbers to be unequal, rather than judging their values. LUA will invoke the corresponding Metamethod only if there are two objects with common metamethod for equality comparisons.

Print always calls ToString to format its output, andToString first checks to see if the object has a metatable with a __tostring field .

table-related metamethod:

(1) __index Metamethod: used more in inheritance. When accessing a domain that does not exist on the table, the LUA interpreter is triggered to find __index metamethod, or nil if it does not exist, otherwise the result will be returned by __index Metamethod.

Window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__index = function (table, key)    return WINDOW[KEY]ENDW = { x = ten, y = 20}setmetatable (w, MT) print (w.width)

You can see that W does not have a width field, but about the associated table MT, and the associated table has __index, so w.width triggers the Mt.__index call (Lua calls the function as the first parameter, width as the second parameter).

__index In addition to being a function, it can be used directly as a table. When __index is a table, Lua looks for the width field directly in the table. So the code can also be written like this:

Window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__index = Windoww = {x = ten, y = 20}setmetatable (w, MT) print (w . width)

The rawget (table, index) function Gets the value of the specified field in the table, which bypasses Metamethod and directly returns the field information for the table, as shown in the following example:

Window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__index = function (table, key) return Window[key] Endw = {x = y = 20}setmetatable (w, MT) print (w.width)                    --100 print (rawget (w, "width"))        --nilPrint (Rawget (w, "X "))            --10

Looking at the penultimate line above, Rawget (W, "width") accessing a nonexistent domain does not trigger a lookup __index.

  (2) __newindex Metamethod:__newindex Metamethod is used to update the table, and__index is used to access the table.

  When assigning a value to a nonexistent field of a table (such as W.add = 1), the LUA lookup __newindex is triggered, and if there is no __newindex, the table is added as a normal assignment behavior.

(1) There is no __newindex, as the general assignment behavior causes the table to add a field (W has a domain Add, the value is 1)

(2) If there is __newindex, the assignment operation is not performed, but the assignment operation is intercepted by __newindex and the __newindex is called (table, domain name, value) as a parameter.

  That is to say, __newindex can make any addition to the table the behavior of the elements to go through __newindex, which is really a good check.

  The Rawset (t, K, v) function is also an operation equivalent to an assignment (W.add = 1 equals rawset (W, "Add", 1)), but calling the function bypasses Metamethod, which does not cause a call to __newindex:

Mt = {}mt.__newindex = function (table, key, value)    rawset (table, key, value)--this cannot be written as Table.key = value; Assigning an operation to a non-existent field causes __newindex to be called, and thus into a dead loop ENDW = {x = ten, y = 20}setmetatable (w, mt) W.add = 1print (w.add)            --1

Like __index, __newindex can also be a table, and if __newindex is a table, it will result in an assignment to the specified table instead of the original table.

Window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__newindex = Windoww = {x = ten, y = 20}setmetatable (w, MT) w.ad D = 1print (W.add)                --nilprint (window.add)            --1

The assignment action causes Windows to add an element of add, and w does not affect it.

When __index and __newindex are mixed, be sure to distinguish between what each behavior is doing:

Window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__index = Windowmt.__newindex = Windoww = {x = ten, y = 20}setm Etatable (W, mt) W.add = 1print (w.add)                --1print (window.add)            --1

When __newindex is a table, w.add=1 indicates that add is added to the window, but access to the window's add is also available through __index,w.

Let's look at the following example:

Window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__index = function (table, key)    return Window[key]endmt.__n Ewindex = function (table, key, value)    rawset (table, key, value) ENDW = {x = ten, y = 20}setmetatable (w, mt) W.add = 1prin T (W.add)-            -1print (Window.add)-        -Nil

When __newindex is a function, W.add adds the Add field directly to W, but window does not exist Add. So the conclusion is: when __newindex is a function, add a field to the target table W, and when __newindex is a table, add a field to the table.

about __index and __newindex must pay attention to distinguish, when to enter the __index, when to enter the __newindex:

window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__index = function (table, key)    print ("Going here __index")    return WINDOW[KEY]ENDW = {x = ten, y = 20}setmetatable (w, MT)= w.width                         --going here __index Access statement will Enter __indexw.width = 1                              --the assignment statement does not enter __index, which causes the W table to add the Width field print (w.width)-                        1print (Rawget (w, "width"))            --1print (window.width)-                -100

  The access statement enters __index, and the assignment statement does not enter __index.

Mt = {}mt.__newindex = function (table, key, value)    print ("Going here __newindex")    rawset (table, key, value) ENDW = {x = ten, y = 20}setmetatable (w, MT) s = W.add                             --The Access statement does not enter __newindexw.add = 1                            --going here __newindex assignment statement enters __newi Ndexprint (W.add)-                        -1print (Rawget (w, "add")-            -1

The assignment statement enters _newindex, and the access statement does not enter __newindex.

It is easy to understand the following example in conjunction with these two words:

window = {x = 0, y = 0, Width = +, height = 100}mt = {}mt.__index = function (table, key)    print ("Going here __index")    return window[key]endmt.__newindex = function (table, key, value)    print ("Going here __newindex")    Rawset ( Table, key, value) ENDW = {x = ten, y = 20}setmetatable (w, MT) s = w.width                            --going here __indexw.width = 1                            --going Here __newindexprint (w.width)--                        1print (Rawget (w, "width"))            --1

The penultimate statement w.width = 1 does not enter __index, so it causes the new domain width to be added to the W table. That is, __index logic does not affect __newindex's judgment, although __index can access the width of the domain, but __newindex still does not have a width field of W.

These concepts are very much around, and Lua is a weakly typed language, so for the specific behavior of many concepts you must test yourself and not be taken for granted.

Http://www.cnblogs.com/sifenkesi/p/3834128.html

MetaTable and Metamethod (EXT)

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.