“Lua 不执行原始赋值”的含义在 2.4 中关于 __newindex

问题描述

来自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)分隔