Lua全局变量__newindex只被调用一次

在“七周七语言”中完成Lua练习,并卡在了元表问题上。

挑战是为了能够连接表格(就像它们是数组一样),重载+运算符,将其+起来。

{ 1, 2, 3 } + { 4, 5, 6 } -- { 1, 2, 3, 4, 5, 6 }

所以我尝试使用__add元方法,并创建了一个包含它的元表。

local mt = {
  __add = function(lhs, rhs)
    return concatenate(lhs, rhs)
  done
}

我错误地尝试将此元表设置在全局表上,但这显然并未向下传播到所有其他表格。

为了将其添加到所有已创建的表上,我在_G上创建了一个单独的元表,它将使用__newindex元方法,然后在每次激活__newindex时设置原始元表。

setmetatable(_G, {
  __newindex = function(array, index)
    setmetatable(array, mt)
  end
})

然而,这没有起作用:

a1 = { 1, 2, 3 }
a2 = { 4, 5, 6 }
a1 + a2

并导致以下错误:attempt to perform arithmetic on global 'a1' (a nil value)

所以,我在全局元表中加入了一个print语句,以查看它是否实际被调用:

setmetatable(_G, {
  __newindex = function(array, index)
    print('new table ' .. index)
    setmetatable(array, mt)
  end
})

这仅会打印创建的第一个表:

a1 = { 1, 2, 3 }
a2 = { 4, 5, 6 }
a3 = { 4, 5, 6 }
a4 = { 4, 5, 6 }

结果为:

new table a1

我认为我是无意中覆盖了某些内容,因为当我删除对setmetatable的调用时

setmetatable(_G, {
  __newindex = function(array, index)
    print('new table ' .. index)
    --setmetatable(array, mt)
  end
})

它按预期打印所有条目。

点赞
用户298029
用户298029
当你执行 `a1 = { 1, 2, 3 }` 时, `__newindex` 函数会被调用, `array` 会被赋值为 `_G` , `index` 会被赋值为 'a1'. 然后调用 `setmetatable(array, mt)` 会改变 `_G` 的元表, 从而撤销原始的 `setmetatable` 调用的效果。

你可能想要像下面这样的代码:

setmetatable(_G, { __newindex = function(array, index) setmetatable(array[index], mt) end })


但是还有另一个问题, 因为现在不再发生原始的赋值操作。 `__newindex` 被调用了, 所以 `a1` 仍然是空值。

你可以在 `__newindex` 函数中尝试使用 `array[index] = value`,但这将再次调用相同的 `__newindex`。因此,请使用 `rawset`:

setmetatable(_G, { __newindex = function(array, index, value) rawset(array, index, value) setmetatable(array[index], mt) end })

```

请注意,__newindex 有三个参数。

现在,当将非表格分配给全局变量时,例如 b = 1,会发生什么?

2015-03-29 17:55:52