目录

Lua初探-元表和元方法


Metatables and Metamethods
  • 每一个值在Lua中都有一个元表。该表是一个定义了原始值下的一些指定操作的普通Lua表,你可以通过覆盖元表中指定的字段的值来更改一些操作行为。例如, 当一个不为零的值作为一个加法的操作数时,Lua会检测该值得metatble得_add方法,如果找到一个,Lua将调用此函数来执行增加。

  • 在metatable中每一个事件的key都是一个事件名称前缀为两个下划线的字符串;相应的值成为metamethods。在前面的示例中,键是__add,metamethd是执行加法操作的方法,除非另有说明,否则metamethods都是一个值。

  • 你可以使用getmetatable方法去查询metatable的任意值。Lua在元表中查询元方法是通过原始的访问方式获取,因此,当要检索对象o中ev事件的元方法,Lua通过使用rawget(getmetatble(o) or {},‘__ev’);

  • 你可以使用setmetatable去替换metatable。你不能在Lua代码中更改其他类型的元表,但你可以使用C的API去实现该需求。

  • 表和full userdata具有单独的元表(尽管多个表和userdata可以共享其元表)。所有其他类型的值,每种类型共享一个metatable; 也就是说,所有数字都共享一个metatable;默认情况下,一个值没有metatable,但是字符串库为字符串类型设置了metatable

  • 一个metatable 控制了一个对象的算术操作,位操作,排序,连接、长度操作、调用和索引;一个metatable也可以定义一个当一个userdata或者表被作为垃圾回收时触发的回调函数。

  • 对于所有的一元运算(否定、长度、和按位NOT),元方法是通过使用一个虚拟的第二操作数来与第一个操作数做比较来进行计算和调用。这额外的操作只是为了去简化Lua的内部实现。

  • 接下来给出由metatables控制的详细事件列表,每一个操作都是由对象的key进行定义:

方法名称 描述
__add 加法操作符。作为加法操作符的任何操作数如果不是一个数字(或者不是一个可转换为数字的字符串),Lua将尝试去调用一个metamethod。调用如下:首先,Lua将检测第一个操作数(即使该操作数是有效的)。如果第一个操作数没有定义一个__add的元方法,Lua将检测第二个操作数,如果第二个操作数发现了__add元方法,Lua将调用__add方法并以两个操作数作为参数并返回一个结果值,否则则将抛出错误
__sub 减法操作符。行为与加法类似
__mul 乘法操作符。行为与加法类似
__div 除法操作符。行为与加法类似
__mod 取莫操作符。行为与加法类似
__pow 乘方操作符。行为与加法类似
__unm 取负操作符。行为与加法类似
__idiv 与除法操作符类似,结果是小数。行为与加法类似
__band 位与操作符。行为与加法类似
__bor 位或操作符。行为与加法类似
__bxor 位亦或操作符。行为与加法类似
__bnot 非操作符。行为与加法类似
__shl 位左移。行为与加法类似
__shr 位右移。行为与加法类似
__concat 连接作符。行为与加法类似,除了在操作数既不是字符串又不是数值时Lua将尝试调用元方法进行转换外,Lua总是期望转换成一个字符型串
__len 长度操作。如果对象不是一个字符串,Lua将尝试调用元方法,如果它是一个元方法,Lua会使用该对象作为参数进行调用,并返回结果,如果不存在元方法但该对象是一个表,Lua将使用表长度的操作方法,否则Lua抛出错误
__eq 等于操作。行为与加法类似,除了Lua仅在被比较的值既是table也是两个full userdata 并且它们不是原始相等时才尝试元方法。 调用的结果总是转换为布尔值。
__lt 小于操作。行为与加法类似,除了Lua仅在被比较的值既不是数字也不是字符串是会尝试调用元方法,返回值总是转换为布尔值
__le 小于等于操作 <=。该操作不像其他的操作,小于等于操作可以使用两个不同的事件,第一个,Lua在两个操作数中查找__le元方法,就像<操作一样,如果未能找到该元方法,Lua将尝试__lt元方法,假设a<=b是等价于 not (b<a).其结果为布尔类型
__index 索引操作table[key]。当table不是一个table或者当key不存在与table中时,Lua将到table中查找元方法
__newindex 索引分配操作table[key]=value。行为类型index
__call 调用操作func(args。当Lua尝试去调用一个非函数值时,该func不是一个方法。Lua将去查找func元方法。如果存在,Lua将调用该原方法并以func作为第一个参数,原始参数通过调用(args)