Lua 闭包引用同一语句中声明的变量失败的问题

这是关于 Lua 中闭包的问题。我在尝试制作一个对象注册器对象时遇到了一个问题(以及解决方法),如下所示:

tracker = {
   objList = {},
   myRegister = function(self, obj)
      table.insert(self.objList, obj)
      return "hello"
   end,
   myInit = function(self)
      local i, obj
      for i, obj in ipairs(self.objList) do
         obj:init()
      end
   end,
}

-- 注意:如下代码*不*工作。
--       如果将其一分为二则*可以*工作,如下所示:
--           local myvar
--           myvar = tracker:myRegister({
local myvar = tracker:myRegister({
      init = function(self)
         -- 这会引发一个错误, complaining that myvar
         -- 是一个具有"nil"值的全局变量
         print("myvar = " .. myvar)
      end,
})

tracker:myInit()

看起来,如果我在创建闭包的同一语句中声明了局部变量"myvar",那么这个局部变量就无法从闭包中访问。然而,如果我只是赋值给一个已经存在的局部变量,那么该变量就可以从闭包中访问。

显然,我知道如何解决这个问题:只需单独声明 myvar。

然而,我的问题是:为什么这是必要的?这是设计上的问题,还是编译器和/或虚拟机中的错误?如果它是设计上的,那么在哪里有记录?我特别关注这种行为是否具有其他影响以及这些影响可能是什么,希望文档(再次假定这是预期的行为)可以阐明这一点。

点赞
用户1847592
用户1847592

是的,这是预期的行为。

这在Lua手册 §3.5 - 可见性规则 中有记录。

此功能允许您编写以下代码:

print"Beginning of log"
do
   local print =
      function(...)
         print(os.date"%T", ...)  -- 在此处调用全局“print”
      end
   -- 在此do-end块内,“print”自动添加当前时间
   print"Some event"
   print"Another event"
end
print"End of log"

换句话说,在创建遮蔽对象时,原始对象仍然可以访问。

这非常有用。

2019-02-09 09:02:17