2.4中"Lua does not perform the primitive assignment."的含义(关于__newindex)

Meaning of "Lua does not perform the primitive assignment." in 2.4 (concerning __newindex)

来自 https://www.lua.org/manual/5.3/manual.html 见第 2.4 节。关于元方法操作 __newindex 陈述了以下引用:

__newindex: The indexing assignment table[key] = value. Like the index event, this event happens when table is not a table or when key is not present in table. The metamethod is looked up in table.

Like with indexing, the metamethod for this event can be either a function or a table. If it is a function, it is called with table, key, and value as arguments. If it is a table, Lua does an indexing assignment to this table with the same key and value. (This assignment is regular, not raw, and therefore can trigger another metamethod.)

Whenever there is a __newindex metamethod, Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)

其中我问下面具体想说的是什么

"Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)"

这是否意味着如果值是一个数字,它是一个原始值,它不会通过元方法事件分配给提供的 table 而我们必须使用 rawget 或其他东西?这让我非常困惑和矛盾。

我想展示相同的示例来帮助您弄清这种困惑。 原始赋值示例:

local test = {}
test['x'] = 1 -- equal to rawset(test, 'x', 1)
print(test['x']) -- 1
print(rawget(test,'x')) -- 1

当 table test 没有 __newindex 元方法时,原始分配代码 test['x'] = 1 等于 rawset(test, 'x', 1)

然后 __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'].

的零结果

如果__newindex函数调用rawset:

local test = {}
setmetatable(test, {
  __newindex = function(t,key,value) 
                 rawset(t,key,value) -- t:test key:'x' value:1
               end})
test['x'] = 1
print(test['x']) -- 1
print(rawget(test,'x')) -- 1

代码与第一个例子效果相同。 所以手册说:

"Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)"

那么问题来了,我们如何使用__newindex呢? table.

中可以用来分隔新旧索引
local test = {y = 1}
local newtest = {}
setmetatable(test, {
    __newindex = 
        function(t,key,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)

分隔