1. 程式人生 > 實用技巧 >關於lua的__index和元表的關係

關於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