Lua元方法__newindex
上篇部落格我們講了__index用於查詢,這一節我們講_newindex , _newindex 元方法用來對錶更新,__index則用來對錶訪問 。
當你給表的一個缺少的索引賦值,直譯器就會查詢__newindex 元方法:如果存在則呼叫這個函式而不進行賦值操作。
我們先來看下簡單的賦值操作
father = { house=1, sayHello = function() print("大家好,我是father."); end } father.__index = father son = { car=1 } son.sayHello = function() print("大家好,我是son."); end setmetatable(son, father) --把son的metatable設定為father print(son.sayHello())
輸出值為:大家好,我是son.
我們呼叫son.sayHello,雖然son可以通過元表找到這個欄位,但是它本身不存在這個欄位,但這並影響我們給他賦值,最後呼叫sayHello成功顯示
如果我們不想給son中不存在的欄位賦值的時候如何檢測呢,這時候元方法__newindex就派上用場了,示例程式碼如下:
local father = { house=1, sayHello = function() print("大家好,我是father."); end } local temp ={ __index = father, __newindex = function(table, key) print(key .. "欄位是不存在的,不允許給它賦值!"); end } son = { car=1 } setmetatable(son, temp) --把son的metatable設定為father son.sayHello = function() print("大家好,我是son."); end son.sayHello()
當我們給sayHello賦值的時候呼叫了__newindex元方法,代替了賦值操作,表son中確實不存在sayHello欄位,只是因為它的元表中有而已,因此當我們給sayHello賦值時,lua判斷sayHello不存在回去呼叫元表裡的__newindex方法,當然了,這裡的__newindex賦值不一定時function,也可以時另外一個表比如
local pt = { house = 2 } local father = { house=0, sayHello = function() print("大家好,我是father."); end } local temp ={ __index = father, __newindex = pt } son = { car=1 } setmetatable(son, temp) --把son的metatable設定為father print("賦值前:" .. pt.house); son.house = 10; print("賦值後:" .. pt.house); print("son.house:" .. son.house);
輸出如下:
賦值前:2
賦值後:10
son.house:0
可以看到,當我們給son.house賦值時實際上是給pt.house賦值了。son.house本身不存在,取的是father的house值
這裡再引用下菜鳥教程中的例子加深理解下
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)
輸出:
value1
nil 新值2
新值1 nil
當我們給mytable.newkey賦值時,會直接將值賦給mymetatable 的newkey欄位,mytable本身沒有這個欄位
當我們給mytable.key1賦值時會直接覆蓋已有值而不呼叫元方法 __newindex,此時mymetatable為nil
最後給個例子加深下理解
local pt = {
house = 2
}
local father = {
sayHello = function()
print("大家好,我是father.");
end
}
local temp ={
__index = father,
__newindex = function()
end
}
son = {
car=1
}
setmetatable(son, temp)
son.house = 10;
print("son.house:" .. son.house);
至此我們很容易判斷出son因為沒有house欄位會報錯,如果把temp中__newindex欄位賦值去掉,則能正常打印出10
簡單總結下:
如果__newindex是一個函式,則在給table不存在的欄位賦值時,會呼叫這個函式。
如果__newindex是一個table,則在給table不存在的欄位賦值時,會直接給__newindex的table賦值。
over!