關於lua的__index和元表的關係
阿新 • • 發佈:2020-08-16
一直比較疑惑,當訪問表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