一直比较疑惑,当访问表a中不存在的元素x时,a.__index,mt,mt.__index是怎么查询的?
先上结论:当访问table a中不存在的元素时,既不会查询a的__index,也不会查询a元表的其他元素,只会查询a元表的__index。
Lua 查找一个表元素时的规则,其实就是如下3个步骤
1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回nil,有元素则继续。
3.判断元表有没有__index,如果__index为nil ,则返回nil;否则
如果__index是一个函数,则返回该函数的返回值,参数为表本身和查找的key。
如果__index是一个表,则重复1、2、3。
如果__index不是函数和表,则报错attempt to index a xxx value
a = {} print(a.x) -- nil a.__index = 1 print(a.x) --nil,不访问自身的__index a.__index = {x = 2} print(a.x) --nil,不访问自身的__index mt = {x = 3} setmetatable(a, mt) print(a.x) -- nil,不访问元表的对象 mt = {x = 4} mt.__index = 5 setmetatable(a, mt) --print(a.x) --error:attempt to index a number value,如果元表的__index不是方法,当做table处理,所以这边报错了 mt.__index = {x = 7} setmetatable(a, mt) print(a.x) --7,成功访问到元表的__index对应的表{x = 7}
那么lua一般的继承实现中的代码就好理解了:
1.setmetatable(cls, {__index = super})为什么不是setmetatable(cls, super),因为前者访问的是super,后者访问的是super.__index.
2.cls.__index = cls,因为最终返回的是instance,而instance = setmetatable({}, cls)。如果不加上这句,反问instance中不存在的元素时,只会在cls.__index = nil中查找,永远也查不到父类。
local cls
if super then cls = {} setmetatable(cls, {__index = super}) cls.super = super else cls = {ctor = function() end} end cls.__cname = classname cls.__ctype = 2 -- lua cls.__index = cls function cls.ToString(self) return self.__cname end function cls.new(...) local instance = setmetatable({}, cls) instance.class = cls instance:ctor(...) return instance end
return cls