Lua закрытие ссылки на переменную завершается неудачно, если объявлено в том же операторе, объявляющем переменную - PullRequest
0 голосов
/ 09 февраля 2019

Это вопрос о замыканиях в Луа.Я наткнулся на проблему (и обходной путь) при попытке сделать объект регистратора объектов следующим образом:

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 отдельно.

Мой вопрос, однако, заключается в следующем: зачем это нужно?Это от замысла или это ошибка компилятора и / или виртуальной машины?Если это задумано, где это задокументировано?Меня особенно интересует, имеет ли это поведение другие последствия, и каковы они могут быть, и я надеюсь, что документация (опять же, предполагая, что это предполагаемое поведение) позволит пролить некоторый свет на это.

1 Ответ

0 голосов
/ 09 февраля 2019

Да, это предполагаемое поведение.
Это задокументировано в руководстве Lua §3.5 - Правила видимости

Эта функция позволяет написать следующий код:

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"

Другими словами, пока создается теневой объект, исходный объект все еще доступен.
Это весьма полезно.

...