问题描述
来自https://www.lua.org/manual/5.3/manual.html 见第 2.4 节。关于元方法操作 __newindex 声明如下:
__newindex:索引赋值表[key] = value。与 index 事件一样,当 table 不是 table 或 key 不是时会发生此事件 存在于表中。在表中查找元方法。
与索引一样,此事件的元方法可以是 函数或表。如果是函数,则用表调用, 键和值作为参数。如果是表,Lua 会做索引 使用相同的键和值分配给该表。 (这个任务 是常规的,而不是原始的,因此可以触发另一个元方法。)
每当有 __newindex 元方法时,Lua 不会执行 原始赋值。 (如有必要,元方法本身可以调用 rawset 来完成任务。)
我问下面具体想说什么
"Lua 不执行 原始赋值。 (如有必要,元方法本身可以调用 rawset 来完成任务。)"
这是否意味着如果值是一个数字,这是一个原始类型,它不会通过元方法事件分配给提供的表,我们必须使用rawget什么的?这对我来说非常混乱和矛盾。
解决方法
我想展示相同的示例来帮助您解决这个困惑。 原始赋值示例:
local test = {}
test['x'] = 1 -- equal to rawset(test,'x',1)
print(test['x']) -- 1
print(rawget(test,'x')) -- 1
当表test['x'] = 1
没有rawset(test,1)
元方法时,原始赋值代码test
等于__newindex
。
然后是 __newindex
元方法示例:
local test = {}
setmetatable(test,{__newindex = function(t,key,value) end})
test['x'] = 1
print(test['x']) -- nil
print(rawget(test,'x')) -- nil
赋值 test['x'] = 1
将触发调用 __newindex
函数。
如果 __newindex
什么都不做,那么什么都不发生,我们将得到 test['x']
的 nil 结果。
如果 __newindex
函数调用 rawset
:
local test = {}
setmetatable(test,{
__newindex = function(t,value)
rawset(t,value) -- t:test key:'x' value:1
end})
test['x'] = 1
print(test['x']) -- 1
print(rawget(test,'x')) -- 1
代码与第一个示例的效果相同。 所以手册上说:
“Lua 不执行原始赋值。(如果需要,元方法本身可以调用 rawset 来完成赋值。)”
那么问题来了,我们如何使用__newindex
?
可用于分隔表中的新旧索引。
local test = {y = 1}
local newtest = {}
setmetatable(test,{
__newindex =
function(t,value)
newtest[key] = value
end,__index = newtest
})
test["x"] = 1
print(test['x']) -- 1
print(test['y']) -- 1
print(rawget(test,'x')) -- nil
print(rawget(test,'y')) -- 1
旧索引'x'和新索引'y'都可以通过test[key]
访问,并且可以用rawget(test,key)
分隔