关于lua的__index和元表的关系

一直比较疑惑,当访问表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

 

posted @ 2020-08-16 11:16  柯腾_wjf  阅读(467)  评论(0编辑  收藏  举报