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的方法.

相关文章
相关标签/搜索