Прямое определение функции в Lua?

#lua #forward-declaration #coronasdk

#lua #прямое объявление #coronasdk

Вопрос:

Как мне вызвать функцию, которую необходимо вызвать поверх ее создания? Я читал что-то о пересылке объявлений, но Google не помогает в этом случае. Каков правильный синтаксис для этого?

Ответ №1:

Lua — это динамический язык, а функции — это просто своего рода значение, которое может быть вызвано с помощью () оператора. Таким образом, вам на самом деле не нужно переадресовывать объявление функции, достаточно убедиться, что переменная в области видимости при ее вызове является той переменной, о которой вы думаете.

Это вообще не проблема для глобальных переменных, содержащих функции, поскольку глобальная среда — это место по умолчанию, где можно искать разрешение имени переменной. Однако для локальных функций вам нужно убедиться, что локальная переменная уже находится в области видимости в лексической точке, где вам нужно вызвать значение, которое она хранит, а также убедиться, что во время выполнения она действительно содержит значение, которое можно вызвать.

Например, вот пара взаимно рекурсивных локальных функций:

 local a,b
a = function() return b() end
b = function() return a() end
  

Конечно, это также пример использования конечных вызовов для обеспечения бесконечной рекурсии, которая ничего не делает, но суть здесь в объявлениях. Благодаря объявлению переменных с local перед тем, как в них будет сохранена функция, эти имена, как известно, являются локальными переменными в лексической области видимости остальной части примера. Затем сохраняются две функции, каждая из которых ссылается на другую переменную.

Комментарии:

1. Хорошо, спасибо. Мне удалось разобраться в этом самостоятельно, но, тем не менее, этот ответ был полезен.

Ответ №2:

Вы можете переадресовать объявление функции, объявив ее имя перед объявлением фактического тела функции:

 local func1
local func2 = function()
  func1()
end
func1 = function()
  --do something
end
  

Однако прямые объявления необходимы только при объявлении функций с локальной областью видимости. Обычно это то, что вы хотите сделать, но Lua также поддерживает синтаксис, больше похожий на C, и в этом случае прямое объявление не требуется:

 function func2()
  func1()
end
function func1()
  --do something
end
  

Комментарии:

1. На самом деле, ваш первый пример не делает того, что вы думаете, поскольку второй local func1 объявляет новую переменную с таким именем и оставляет первую func1 осиротевшей и по-прежнему имеющей значение nil .

2. Ваш второй пример тоже плох, потому что сработал бы наивный вызов «func2» из-под func1, но не из-за какого-либо «прямого объявления». Скорее, func1 объявлен в глобальной среде (_G), и когда func2 ищет func1, он проверяет _G . Это означает, что func1 объявляется до запуска func2 и, следовательно, когда он проверяет _G, он работает. Выполнение вызова func2 сразу после определения func2 приводит к ошибке… потому что func1 не объявлен / определен.

3. Вот почему я сказал «Однако прямые объявления необходимы только при объявлении функций с локальной областью видимости». Другими словами, я явно говорил, что во втором примере не используется прямое объявление.

Ответ №3:

При тестировании со встроенным lua во Freeswitch, прямое объявление не работает:

 fmsg("CRIT", "It worked.")
function fmsg(infotype, msg)
   freeswitch.consoleLog(infotype,  msg .. "n")
end
  

Результат:

[ОШИБКА] mod_lua.cpp:203 /usr/local/freeswitch/scripts/foo.lua:1: попытка вызвать глобальный ‘fmsg’ (нулевое значение)

Изменение порядка действительно работает.

Ответ №4:

Чтобы понять, как работает прямое обращение в Lua по сравнению с C, вы должны понимать фундаментальное различие между компиляцией C и выполнением Lua.

  • В C прямая ссылка — это механизм времени компиляции. Следовательно, если вы включите шаблон прямого объявления в модуль C, то любой из ваших следующих кодов будет использовать этот шаблон при компиляции вызова. Вы можете включать или не включать реализацию функции в один и тот же модуль, и в этом случае оба объявления должны быть семантически идентичны, иначе компилятор выдаст ошибку. Поскольку это конструкция времени компиляции, скомпилированный код может выполняться в любом порядке.

  • В Lua прямая ссылка — это механизм времени выполнения, заключающийся в том, что скомпилированная функция генерирует прототип функции внутри кода, но он доступен только как переменная Lua во время выполнения или значение после того, как выполнение прошло через объявление, создающее закрытие Lua. Здесь порядок объявления в исходном коде не имеет значения. Важен порядок выполнения: если замыкание еще не было привязано к переменной, то выполнение выдаст исключение «нулевое значение».
    Если вы используете локальную переменную для хранения значения функции, то по-прежнему применяются обычные локальные правила определения области видимости: local объявление должно предшествовать его использованию в исходном коде и должно находиться в пределах области видимости, иначе компилятор скомпилирует неверную глобальную или внешнюю локальную ссылку. Итак, прямая ссылка с использованием локальных файлов, как обсуждалось в другом ответе, будет работать, но только если протоны привязаны к замыканиям до выполнения первого вызова.

Ответ №5:

У меня не работает, если я пытаюсь вызвать функцию до определения. Я использую этот скрипт Lua в nginx conf.

поток ввода lua прерван: ошибка времени выполнения: lua_redirect.lua:109: попытка вызвать глобальный ‘throwErrorIfAny’ (нулевое значение)

Фрагмент кода —

 ...
throwErrorIfAny()
...

function throwErrorIfAny()
    ngx.say("request not allowed")
    ngx.exit(ngx.HTTP_OK)
end
  

Учитывая, что в некоторых других ответах также указывалось, что у них это тоже не сработало, возможно, что прямое объявление Lua не работает с другими инструментами.

PS: Все работает нормально, если я помещаю определение функции перед, а затем вызываю ее после wards.

Ответ №6:

Если вы используете ООП, вы можете вызвать любой элемент функции до ее «определения».

 local myClass = {}
local myClass_mt = { __index = myClass }

local function f1 (self)

    print("f1")
    self:later() --not yet "delared" local function
end

local function f2 (self)

    print("f2")
    self:later() --not yet "declared" local function   
end
--...
--later in your source declare the "later" function:
local function later (self)

    print("later")   
end

function myClass.new()    -- constructor
    local this = {}

    this = {
        f1 = f1,
        f2 = f2,
        later = later,  --you can access the "later" function through "self"
    }

    setmetatable(this, myClass_mt)

    return this
end

local instance = myClass.new()

instance:f1()
instance:f2()
  

Вывод программы:

 f1
later
f2
later