首页 > 解决方案 > 如果在声明变量的同一语句中声明,对变量的 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,
}

-- Note: As written, this does *not* work.
--       It *will* work if I separate the line into two parts as follows:
--           local myvar
--           myvar = tracker:myRegister({
local myvar = tracker:myRegister({
      init = function(self)
         -- This will generate an error complaining that myvar
         -- is a global variable with a "nil" value
         print("myvar = " .. myvar)
      end,
})

tracker:myInit()

似乎如果我在创建闭包的同一语句中声明局部变量“myvar”,则无法从闭包访问局部变量。但是,如果我只是分配给一个已经存在的局部变量,那么该变量可以从闭包中访问。

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

然而,我的问题是:为什么这是必要的?这是设计使然,还是编译器和/或虚拟机中的错误?如果是设计使然,它在哪里记录?我对这种行为是否有其他影响以及可能是什么特别感兴趣,我希望文档(再次假设这是预期的行为)能够对此有所了解。

标签: variablesluaclosureslocal

解决方案


是的,这是预期的行为。
它记录在 Lua 手册§3.5 – Visibility Rules

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

print"Beginning of log"
do
   local print = 
      function(...) 
         print(os.date"%T", ...)  -- Here you're invoking global "print"
      end
   -- inside this do-end block "print" is automatically adding current time 
   print"Some event"
   print"Another event"
end
print"End of log"

换言之,在创建阴影对象时,仍可访问原始对象。
这非常有用。


推荐阅读