Lua 5.2元表和环境

我有一个这样的结构:

context = {
  pi = math.pi,
  sin = math.sin,
  cos = math.cos,
  tan = math.tan,
  print = print
}

modules = {
  m1 = {
    variables = { x = 1 },
    update = function(self)
      local _ENV = self.variables
      x = 2
      m2.x = 2
    end
  },
  m2 = {
    variables = { x = 1 },
    update = function(self)
      local _ENV = self.variables
    end
  }
}

setmetatable(modules.m1, {__index = modules.m1.variables})
setmetatable(modules.m1.variables, {__index = context})

setmetatable(modules.m2, {__index = modules.m2.variables})
setmetatable(modules.m2.variables, {__index = context})

setmetatable(context, {__index = modules})

这个想法是用户输入代码到UI中,然后该代码粘贴到不同模块的 update 函数中,在 local _ENV 设置后面。这些用户输入的代码应该被沙箱化。它应该能够访问一些函数(context 表中的函数)和其他模块的内容。m1:update 中的代码应该能够引用 m1.variables 中的变量,而无需限定它们; 其他模块中的变量(即 m2.variables 中的变量)应该通过限定它们的模块名称(即 m2.x)来访问。

但是我得到的结果是这样的:

$ lua -i test.lua
> = modules.m1.x
1
> = modules.m1.variables.x
1
> = modules.m2.x
1
> = modules.m2.variables.x
1
> = modules.m1:update()
> = modules.m1.x
2
> = modules.m1.variables.x
2
> = modules.m2.x
2
> = modules.m2.variables.x
1

为什么 modules.m2.variables.x 没有被更新?而且,如果像看起来那样,modules.m2.xmodules.m2.variables.x 不同,那么 modules.m2.x 从哪里来?

点赞
用户1442917
用户1442917

modules.m2.variables.x 没有被更新,因为你只设置了 __index 元方法(用于检索不存在的键),而没有设置 __newindex 元方法(用于赋值给不存在的键),因此结果是值被存储在 modules.m2.x 表中而不是你期望的 modules.m2.variables.x 表中。

如果我添加了 __newindex,如 setmetatable(modules.m2, {__index = modules.m2.variables, __newindex = modules.m2.variables}),我会得到预期的结果。

2015-04-15 06:21:05