首页 > 解决方案 > “Lua 不执行原始分配”的含义。在 2.4 中(关于 __newindex)

问题描述

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

__newindex:索引分配表[key] = value。与索引事件一样,当表不是表或表中不存在键时,会发生此事件。元方法在表中查找。

与索引一样,此事件的元方法可以是函数或表。如果它是一个函数,则使用表、键和值作为参数调用它。如果它是一个表,Lua 会使用相同的键和值对该表进行索引分配。(这个赋值是常规的,不是原始的,因此可以触发另一个元方法。)

只要有 __newindex 元方法,Lua 就不会执行原语赋值。(如有必要,元方法本身可以调用 rawset 进行赋值。)

其中我问下面的具体打算说什么

“Lua 不执行原始赋值。(如果需要,元方法本身可以调用 rawset 来进行赋值。)”

这是否意味着如果该值是一个数字,这是一个原语,它不会通过元方法事件分配给提供的表,我们必须使用 rawget 什么的?这对我来说非常混乱和矛盾。

标签: apiluamanual

解决方案


我想展示同样的例子来帮助你弄清楚这种困惑。原始赋值示例:

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, 'x', 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什么都不做,那么什么也不会发生,我们将得到 nil 结果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 不执行原始赋值。(如果需要,元方法本身可以调用 rawset 来进行赋值。)”

那么问题来了,我们该如何使用__newindex呢?它可以用来分隔表中的新旧索引。

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)


推荐阅读