lua中metatables和metamethods

reference:html

http://www.lua.org/manual/5.3/manual.html編程

 

2.4 – Metatables and Metamethods

Every value in Lua can have a metatable. This metatable is an ordinary Lua table that defines the behavior of the original value under certain special operations. You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable. For instance, when a non-numeric value is the operand of an addition, Lua checks for a function in the field "__add" of the value's metatable. If it finds one, Lua calls this function to perform the addition.數據結構

The key for each event in a metatable is a string with the event name prefixed by two underscores; the corresponding values are called metamethods. In the previous example, the key is "__add" and the metamethod is the function that performs the addition.app

You can query the metatable of any value using the getmetatable function. Lua queries metamethods in metatables using a raw access (see rawget). So, to retrieve the metamethod for event ev in object o, Lua does the equivalent to the following code:less

rawget(getmetatable(o) or {}, "__ev")

You can replace the metatable of tables using the setmetatable function. You cannot change the metatable of other types from Lua code (except by using the debug library (§6.10)); you should use the C API for that.ide

Tables and full userdata have individual metatables (although multiple tables and userdata can share their metatables). Values of all other types share one single metatable per type; that is, there is one single metatable for all numbers, one for all strings, etc. By default, a value has no metatable, but the string library sets a metatable for the string type (see §6.4).函數

A metatable controls how an object behaves in arithmetic operations, bitwise operations, order comparisons, concatenation, length operation, calls, and indexing. A metatable also can define a function to be called when a userdata or a table is garbage collected (§2.5).ui

For the unary operators (negation, length, and bitwise NOT), the metamethod is computed and called with a dummy second operand, equal to the first one. This extra operand is only to simplify Lua's internals (by making these operators behave like a binary operation) and may be removed in future versions. (For most uses this extra operand is irrelevant.)this

A detailed list of events controlled by metatables is given next. Each operation is identified by its corresponding key.lua

  • __addthe addition (+) operation. If any operand for an addition is not a number (nor a string coercible to a number), Lua will try to call a metamethod. First, Lua will check the first operand (even if it is valid). If that operand does not define a metamethod for __add, then Lua will check the second operand. If Lua can find a metamethod, it calls the metamethod with the two operands as arguments, and the result of the call (adjusted to one value) is the result of the operation. Otherwise, it raises an error.
  • __subthe subtraction (-) operation. Behavior similar to the addition operation.
  • __multhe multiplication (*) operation. Behavior similar to the addition operation.
  • __divthe division (/) operation. Behavior similar to the addition operation.
  • __modthe modulo (%) operation. Behavior similar to the addition operation.
  • __powthe exponentiation (^) operation. Behavior similar to the addition operation.
  • __unmthe negation (unary -) operation. Behavior similar to the addition operation.
  • __idivthe floor division (//) operation. Behavior similar to the addition operation.
  • __bandthe bitwise AND (&) operation. Behavior similar to the addition operation, except that Lua will try a metamethod if any operand is neither an integer nor a value coercible to an integer (see §3.4.3).
  • __borthe bitwise OR (|) operation. Behavior similar to the bitwise AND operation.
  • __bxorthe bitwise exclusive OR (binary ~) operation. Behavior similar to the bitwise AND operation.
  • __bnotthe bitwise NOT (unary ~) operation. Behavior similar to the bitwise AND operation.
  • __shlthe bitwise left shift (<<) operation. Behavior similar to the bitwise AND operation.
  • __shrthe bitwise right shift (>>) operation. Behavior similar to the bitwise AND operation.
  • __concatthe concatenation (..) operation. Behavior similar to the addition operation, except that Lua will try a metamethod if any operand is neither a string nor a number (which is always coercible to a string).
  • __lenthe length (#) operation. If the object is not a string, Lua will try its metamethod. If there is a metamethod, Lua calls it with the object as argument, and the result of the call (always adjusted to one value) is the result of the operation. If there is no metamethod but the object is a table, then Lua uses the table length operation (see §3.4.7). Otherwise, Lua raises an error.
  • __eqthe equal (==) operation. Behavior similar to the addition operation, except that Lua will try a metamethod only when the values being compared are either both tables or both full userdata and they are not primitively equal. The result of the call is always converted to a boolean.
  • __ltthe less than (<) operation. Behavior similar to the addition operation, except that Lua will try a metamethod only when the values being compared are neither both numbers nor both strings. The result of the call is always converted to a boolean.
  • __lethe less equal (<=) operation. Unlike other operations, the less-equal operation can use two different events. First, Lua looks for the __lemetamethod in both operands, like in the less than operation. If it cannot find such a metamethod, then it will try the __lt metamethod, assuming that a <= b is equivalent to not (b < a). As with the other comparison operators, the result is always a boolean. (This use of the __lt event can be removed in future versions; it is also slower than a real __le metamethod.)
  • __indexThe indexing access table[key]. This event happens when table is not a table or when key is not present in table. The metamethod is looked up in table.

    Despite the name, the metamethod for this event can be either a function or a table. If it is a function, it is called with table and key as arguments, and the result of the call (adjusted to one value) is the result of the operation. If it is a table, the final result is the result of indexing this table with key. (This indexing is regular, not raw, and therefore can trigger another metamethod.)

  • __newindexThe indexing assignment table[key] = value. Like the index event, this event happens when table is not a table or when key is not present in table. The metamethod is looked up in table.

    Like with indexing, the metamethod for this event can be either a function or a table. If it is a function, it is called with tablekey, and value as arguments. If it is a table, Lua does an indexing assignment to this table with the same key and value. (This assignment is regular, not raw, and therefore can trigger another metamethod.)

    Whenever there is a __newindex metamethod, Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)

  • __callThe call operation func(args). This event happens when Lua tries to call a non-function value (that is, func is not a function). The metamethod is looked up in func. If present, the metamethod is called with func as its first argument, followed by the arguments of the original call (args). All results of the call are the result of the operation. (This is the only metamethod that allows multiple results.)

It is a good practice to add all needed metamethods to a table before setting it as a metatable of some object. In particular, the __gc metamethod works only when this order is followed (see §2.5.1).

Because metatables are regular tables, they can contain arbitrary fields, not only the event names defined above. Some functions in the standard library (e.g.,tostring) use other fields in metatables for their own purposes.

getmetatable (object)

If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a __metatable field, returns the associated value. Otherwise, returns the metatable of the given object.

setmetatable (table, metatable)

Sets the metatable for the given table. (To change the metatable of other types from Lua code, you must use the debug library (§6.10).) If metatable is nil, removes the metatable of the given table. If the original metatable has a __metatable field, raises an error.

This function returns table.

 

 

reference:

http://www.cnblogs.com/simonw/archive/2007/01/17/622032.html

什麼是Metatable 

      Lua中Metatable這個概念, 國內將他翻譯爲元表. 元表爲重定義Lua中任意一個對象(值)的默認行爲提供了一種公開入口. 如同許多OO語言的操做符重載或方法重載. Metatable可以爲咱們帶來很是靈活的編程方式. 

      具體的說, Lua中每種類型的值都有都有他的默認操做方式, 如, 數字能夠作加減乘除等操做, 字符串能夠作鏈接操做, 函數能夠作調用操做, 表能夠作表項的取值賦值操做. 他們都遵循這些操做的默認邏輯執行, 而這些操做能夠經過Metatable來改變. 如, 你能夠定義2個表如何相加等. 
      看一個最簡單的例子, 重定義了2個表的加法操做. 這個例子中將c的__add域改寫後將a的Metatable設置爲c, 當執行到加法的操做時, Lua首先會檢查a是否有Metatable而且Metatable中是否存在__add域, 若是有則調用, 不然將檢查b的條件(和a相同), 若是都沒有則調用默認加法運算, 而table沒有定義默認加法運算, 則會報錯.

示例1:

--定義2個表
a = {5, 6}
b = {7, 8}
--用c來作Metatable
c = {}
--重定義加法操做
c.__add = function(op1, op2)
   for _, item in ipairs(op2) do
      table.insert(op1, item)
   end
   return op1
end
--將a的Metatable設置爲c
setmetatable(a, c)
--d如今的樣子是{5,6,7,8}
d = a + b
print(d[1],d[2],d[3],d[4])

執行結果:

5	6	7	8

示例2:

a = {5, 6}
b = {7, 8}
--用c來作Metatable
c = {}
setmetatable(a, c)
d = a + b 

print(d[0], d[1],d[2],d[3],d[4],d[5])

執行結果:

lua: metatable.lua:57: attempt to perform arithmetic on global 'a' (a table value)
stack traceback:
	metatable.lua:57: in main chunk
	[C]: ?

這是因爲Metatable中是不存在__add域,,並且table沒有定義默認加法運算, 因此會報錯.

 

Metatable並不神祕, 他只是一個普通的table, 在table這個數據結構當中, Lua定義了許多重定義這些操做的入口. 他們均以雙下劃線開頭爲table的域, 如上面例子的__add. 當你爲一個值設置了Metatable, 並在Metatable中設置了重寫了相應的操做域, 在這個值執行這個操做的時候就會觸發重寫的自定義操做. 固然每一個操做都有每一個操做的方法格式簽名, 如__add會將加號兩邊的兩個操做數作爲參數傳入而且要求一個返回值. 有人把這樣的行爲比做事件, 當xx行爲觸發會激活事件自定義操做.

Metatable中定義的操做add, sub, mul, div, mod, pow, unm, concat, len, eq, lt, le, tostring, gc, index, newindex, call...

      在Lua中任何一個值都有Metatable, 不一樣的值能夠有不一樣的Metatable也能夠共享一樣的Metatable, 但在Lua自己提供的功能中, 不容許你改變除了table類型值外的任何其餘類型值的Metatable, 除非使用C擴展或其餘庫. setmetatable和getmetatable是惟一一組操做table類型的Metatable的方法.

相關文章
相關標籤/搜索