Lua 学习-10 元表metaTable

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 events. You can change several aspects of the behavior of 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.

在Lua中每个值都有一个metatable对应,metaTable就是是一个普通的table,里面记录了一个值在特定的事件下行为(操作),当然就可以通过修改这个table的字段 来改变这个值 的操作。
例如;当对一个非数值型的值 进行相加运算时,就会去这个值 的metatable中查找 __add 的函数,如果存在就调用这个函数

 

The key for each event in a metatable is a string with the event name prefixed by two underscores; the corresponding value is called a metavalue. For most events, the metavalue must be a function, which is then called a metamethod. In the previous example, the key is the string "__add" and the metamethod is the function that performs the addition. Unless stated otherwise, a metamethod may in fact be any callable value, which is either a function or a value with a __call metamethod.

元表中中的每个事件对应的key(元表key) 都是以两个下划线开始的一个后面跟小写字符构成的字符串,对应的值 的叫做metavalue(元表值),大多数情况下这个值 是一个函数,
这个函数也被 叫做metamethod(元表方法)除非特别说明,元表方法可以是任何可以调用的值,要么是函数要么是一个 __call 的元表方法

 

You can query the metatable of any value using the getmetatable function. Lua queries metamethods in metatables using a raw access (see rawget).

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).

 

查询 元表的值用函数 getmetatable,替换 tables中的metatable 用 setmetatable,

 

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 detailed list of operations controlled by metatables is given next. Each event is identified by its corresponding key. By convention, all metatable keys used by Lua are composed by two underscores followed by lowercase Latin letters.

  • __addthe addition (+) operation. If any operand for an addition is not a number, Lua will try to call a metamethod. It starts by checking the first operand (even if it is a number); 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, if no metamethod is found, Lua raises an error.
  • 如果参与加计算的数据不是数值,Lua就会尝试调用 一个元表方法,顺序是先找第一个值对应的元表,如果没有找到 __add方法,
    就继续找第二个运算对象的原表,如果找到就会把两个操作对象当作参数调用__add方法,并且返回一个值做为操作的结果 ,否则就报错了。

     

  • __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 float 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. Moreover, the result of the call is always converted to a boolean.
  • __lethe less equal (<=) operation. Behavior similar to the less than operation.
  • __indexThe indexing access operation table[key]. This event happens when table is not a table or when key is not present in table. The metavalue is looked up in the metatable of table.

    The metavalue for this event can be either a function, a table, or any value with an __index metavalue. 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. Otherwise, the final result is the result of indexing this metavalue with key. This indexing is regular, not raw, and therefore can trigger another __index metavalue.

  • __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 metavalue is looked up in the metatable of table.

    Like with indexing, the metavalue for this event can be either a function, a table, or any value with an __newindex metavalue. If it is a function, it is called with tablekey, and value as arguments. Otherwise, Lua repeats the indexing assignment over this metavalue with the same key and value. This assignment is regular, not raw, and therefore can trigger another __newindex metavalue.

    Whenever a __newindex metavalue is invoked, Lua does not perform the primitive assignment. If needed, 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 results of the operation. This is the only metamethod that allows multiple results.

 

 

 

"sub": - 操作。 行为和 "add" 操作类似。
"mul": * 操作。 行为和 "add" 操作类似。
"div": / 操作。 行为和 "add" 操作类似。
"mod": % 操作。 行为和 "add" 操作类似。
"pow": ^ (次方)操作。 行为和 "add" 操作类似。
"unm": - (取负)操作。 行为和 "add" 操作类似。
"idiv": // (向下取整除法)操作。 行为和 "add" 操作类似。
"band": & (按位与)操作。 行为和 "add" 操作类似, 不同的是 Lua 会在任何一个操作数无法转换为整数时 (参见 §3.4.3)尝试取元方法。
"bor": | (按位或)操作。 行为和 "band" 操作类似。
"bxor": ~ (按位异或)操作。 行为和 "band" 操作类似。
"bnot": ~ (按位非)操作。 行为和 "band" 操作类似。
"shl": << (左移)操作。 行为和 "band" 操作类似。
"shr": >> (右移)操作。 行为和 "band" 操作类似。
"concat": .. (连接)操作。 行为和 "add" 操作类似, 不同的是 Lua 在任何操作数即不是一个字符串 也不是数字(数字总能转换为对应的字符串)的情况下尝试元方法。
"len": # (取长度)操作。 如果对象不是字符串,Lua 会尝试它的元方法。 如果有元方法,则调用它并将对象以参数形式传入, 而返回值(被调整为单个)则作为结果。 如果对象是一张表且没有元方法, Lua 使用表的取长度操作(参见 §3.4.7)。 其它情况,均抛出错误。
"eq": == (等于)操作。 和 "add" 操作行为类似, 不同的是 Lua 仅在两个值都是表或都是完全用户数据 且它们不是同一个对象时才尝试元方法。 调用的结果总会被转换为布尔量。
"lt": < (小于)操作。 和 "add" 操作行为类似, 不同的是 Lua 仅在两个值不全为整数也不全为字符串时才尝试元方法。 调用的结果总会被转换为布尔量。
"le": <= (小于等于)操作。 和其它操作不同, 小于等于操作可能用到两个不同的事件。 首先,像 "lt" 操作的行为那样,Lua 在两个操作数中查找 "__le" 元方法。 如果一个元方法都找不到,就会再次查找 "__lt" 事件, 它会假设 a <= b 等价于 not (b < a)。 而其它比较操作符类似,其结果会被转换为布尔量。
"index": 索引 table[key]。 当 table 不是表或是表 table 中不存在 key 这个键时,这个事件被触发。 此时,会读出 table 相应的元方法。
尽管名字取成这样, 这个事件的元方法其实可以是一个函数也可以是一张表。 如果它是一个函数,则以 table 和 key 作为参数调用它。 如果它是一张表,最终的结果就是以 key 取索引这张表的结果。 (这个索引过程是走常规的流程,而不是直接索引, 所以这次索引有可能引发另一次元方法。)

"newindex": 索引赋值 table[key] = value 。 和索引事件类似,它发生在 table 不是表或是表 table 中不存在 key 这个键的时候。 此时,会读出 table 相应的元方法。
同索引过程那样, 这个事件的元方法即可以是函数,也可以是一张表。 如果是一个函数, 则以 table、 key、以及 value 为参数传入。 如果是一张表, Lua 对这张表做索引赋值操作。 (这个索引过程是走常规的流程,而不是直接索引赋值, 所以这次索引赋值有可能引发另一次元方法。)

一旦有了 "newindex" 元方法, Lua 就不再做最初的赋值操作。 (如果有必要,在元方法内部可以调用 rawset 来做赋值。)

"call": 函数调用操作 func(args)。 当 Lua 尝试调用一个非函数的值的时候会触发这个事件 (即 func 不是一个函数)。 查找 func 的元方法, 如果找得到,就调用这个元方法, func 作为第一个
参数传入,原来调用的参数(args)后依次排在后面。

 

 

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.

 

对于一元操作符(取负、求长度、位反), 元方法调用的时候,第二个参数是个哑元,其值等于第一个参数。 这样处理仅仅是为了简化 Lua 的内部实现 
(这样处理可以让所有的操作都和二元操作一致), 这个行为有可能在将来的版本中移除。 (使用这个额外参数的行为都是不确定的。)

 

posted on 2023-03-07 13:34  hztech  阅读(31)  评论(0编辑  收藏  举报

导航