上篇博客我们讲了__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!