在談及Lua中的__index,__newindex,rawget和rawset前,需要理解Lua中的元表這個概念。
零、元表的概念
對Lua中元表的解釋: 元表可以改變表的行為模式。
這裡舉個例子:
Window = {}Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}Window.mt = {}function Window.new(o)setmetatable(o ,Window.mt)return oendWindow.mt.__index = Window.prototypeWindow.mt.__newindex = function (table ,key ,value)if key == "wangbin" thenrawset(table ,"wangbin" ,"yes,i am")endendw = Window.new{x = 10 ,y = 20}w.wangbin = "55"print(w.wangbin)
然後,我們可以看到列印資訊是:yes,i am
原本賦值的地方是w.wangbin = "55",但是結果卻是 yes,i am。
這裡就改變了元表的行為模式。
一、__index的理解
__index是:當我們訪問一個表中的元素不存在時,則會觸發去尋找__index元方法,如果不存在,則返回nil,如果存在,則返回結果。
Window = {}Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}Window.mt = {}function Window.new(o)setmetatable(o ,Window.mt)return oendWindow.mt.__index = function (t ,key)-- bodyreturn 1000endw = Window.new{x = 10 ,y = 20}print(w.wangbin)
列印結果是:1000。可以看出,我們在new的時候,w這個表裡其實沒有wangbin這個元素的,我們重寫了元表中的__index,使其返回1000,意思是:如果你要尋找的元素,該表中沒有,那麼預設返回1000。
二、__newindex的理解
__newindex:當給你的表中不存在的值進行賦值時,lua解譯器則會尋找__newindex元方法,發現存在該方法,則執行該方法進行賦值,注意,是使用
Window.mt = {}function Window.new(o)setmetatable(o ,Window.mt)return oendWindow.mt.__index = function (t ,key)return 1000endWindow.mt.__newindex = function (table ,key ,value)if key == "wangbin" thenrawset(table ,"wangbin" ,"yes,i am")endendw = Window.new{x = 10 ,y = 20}w.wangbin = "55"print(w.wangbin)
ok,這裡的列印結果是:yes,i am。w這個表裡本來沒有wangbin這個元素的,我們重寫了元表中__newindex,並在__newindex方法中重新進行賦值操作,然後,我們對這個本不存在的原色w.wangbin進行賦值時,執行__newindex方法的賦值操作,最後,列印結果便是:yes,i am
三、rawget和rawset的理解
是為了繞過__index而出現的,直接點,就是讓__index方法的重寫無效。(我這裡用到"重寫"二字,可能不太對,希望能得到糾正)
Window = {}Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}Window.mt = {}function Window.new(o)setmetatable(o ,Window.mt)return oendWindow.mt.__index = function (t ,key)return 1000endWindow.mt.__newindex = function (table ,key ,value)if key == "wangbin" thenrawset(table ,"wangbin" ,"yes,i am")endendw = Window.new{x = 10 ,y = 20}print(rawget(w ,w.wangbin))
列印結果是:nil。這裡的元表中__index函數就不再起作用了。
但是rawset呢,起什麼作用呢?我們再來運行一段代碼。
Window = {}Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}Window.mt = {}function Window.new(o)setmetatable(o ,Window.mt)return oendWindow.mt.__index = function (t ,key)return 1000endWindow.mt.__newindex = function (table ,key ,value)table.key = "yes,i am"endw = Window.new{x = 10 ,y = 20}w.wangbin = "55"
然後我們的程式就stack overflow了。可見,程式陷入了死迴圈。因為w.wangbin這個元素本來就不存在表中,然後這裡不斷執行進入__newindex,陷入了死迴圈。