cocos2d-x lua —— 元表metatable

Lua表

关于Lua表的介绍,这里有一段出自网络的介绍:

Lua的表本质其实是个类似HashMap的东西,其元素是很多的Key-Value对.
如果尝试访问了一个表中并不存在的元素时,就会触发Lua的一套查找机制,也是凭借这个机制,才能够实现“面向对象”的。

那么有时候我们可能会遇到这样的一段代码:

myTable = {}  
print(myTable.A) --这里试图打印myTable并不存在的成员A  

执行结果:nil

输出为nil的原因很简单,myTable中并没有A这个成员,这符合我们平时对HashMap的认知。但对于Lua表,如果myTable有元表,情况就不同了。

Lua元表

元表像是一个备用查找表,说白了假设表A的元表是B,那么如果在A中找不到的东西就会尝试在B中去找。

  • 在Lua中,metatable是被译作元表,Lua 中的每个值都可以用一个 metatable。这个 metatable 就是一个原始的 Lua table ,它用来定义原始值在特定操作下的行为。
  • 一个 metatable 可以控制一个对象做数学运算操作、比较操作、连接操作、取长度操作、取下标操作时的行为,metatable 中还可以定义一个函数,让 userdata 作垃圾收集时调用它。对于这些操作,Lua 都将其关联上一个被称作事件的指定健。
  • 当 Lua 需要对一个值发起这些操作中的一个时,它会去检查值中 metatable 中是否有对应事件。如果有的话,键名对应的值(元方法)将控制 Lua 怎样做这个操作。

#####metatable通过其包含的函数来给所挂接的table定义一些特殊的操作,包括:

  • __add: 定义所挂接table的加法操作
  • __mul: 定义乘法操作
  • __div: 定义除法操作
  • __sub: 定义减法操作
  • __unm: 定义负操作, 即: -table的含义
  • __tostring: 定义当table作为tostring()函式之参数被呼叫时的行为(例如: print(table)时将呼叫tostring(table)作为输出结果)
  • __concat: 定义连接操作(“..”运算符)
  • __index: 定义当table中不存在的key值被试图获取时的行为
  • __newindex: 定义在table中产生新key值时的行为
这里主要说一下_index

__index:

如果A的元表是B,那么如果访问了一个A中不存在的成员,就会访问查找B中有没有这个成员。

这个过程大体是这样,但却不完全是这样,实际上,即使将A的元表设置为B,而且B中也确实有这个成员,返回结果仍然会是nil

原因就是

B的index元方法没有赋值。按照我的理解,index方法是用来确定一个表在被作为元表时的查找方法

father = {  
    house=1  
}  
son = {  
    car=1  
}  
setmetatable(son, father) --把son的metatable设置为father  
print(son.house) 

输出的结果是nil,但如果把代码改为

father = {  
    house=1  
}  
father.__index = father -- 把father的__index方法指向自己  
son = {  
    car=1  
}  
setmetatable(son, father)  
print(son.house) 

输出的结果为1,符合预期。

在上述例子中,访问son.house时,son中没有house这个成员,但Lua接着发现son有元表father,于是此时father被当做元表来查找.

此时,Lua并不是直接在father中找名为house的成员,而是调用father的index方法,如果index方法为nil,则返回nil,如果是一个表(上例中father的index方法等于自己,就是这种情况),那么就到index方法所指的这个表中查找名为house的成员,于是,最终找到了house成员。

注:index方法除了可以是一个表,还可以是一个函数,如果是一个函数,index方法被调用时将返回该函数的返回值。

相信到这里,应该已经很好理解了。

总结一句就是:index是:当我们访问一个表中的元素不存在时,则会触发去寻找index元方法,如果不存在,则返回nil,如果存在,则返回结果。

补充

  • _newindex:当给你的表中不存在的值进行赋值时,lua解释器则会寻找__newindex元方法,发现存在该方法,则执行该方法进行赋值,注意,是使用rawset来进行赋值,至于原因,后面会讲到。
  • rawget是为了绕过index而出现的,直接点,就是让index方法的重写无效。

Lua查找一个表元素时的规则(出自网络)

  • 1.在表中查找,如果找到,返回该元素,找不到则继续
  • 2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续
  • 3.判断元表有没有index方法,如果index方法为nil,则返回nil;如果index方法是一个表,则重复1、2、3;如果index方法是一个函数,则返回该函数的返回值

参考链接:https://blog.csdn.net/wangbin_jxust/article/details/12108189

坚持原创技术分享,您的支持将鼓励我继续创作!