【问题标题】:Forward define a function in Lua?在 Lua 中前向定义一个函数?
【发布时间】:2011-08-29 08:53:10
【问题描述】:

如何调用需要从其创建之上调用的函数?我读了一些关于前向声明的东西,但谷歌在这种情况下没有帮助。正确的语法是什么?

【问题讨论】:

    标签: lua forward-declaration coronasdk


    【解决方案1】:

    Lua 是一种动态语言,函数只是一种可以用() 运算符调用的值。所以你真的不需要转发声明函数,只要确保你调用它时范围内的变量就是你认为的变量。

    对于包含函数的全局变量,这根本不是问题,因为全局环境是解析变量名的默认位置。然而,对于局部函数,你需要确保局部变量已经在你需要调用它存储的值的词法点的范围内,并且还要确保在运行时它确实持有一个可以调用的值.

    例如,这里有一对相互递归的局部函数:

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

    当然,这也是一个使用尾调用来允许不执行任何操作的无限递归的示例,但这里的重点是声明。通过在其中存储函数之前使用local 声明变量,这些名称在示例的其余部分的词法范围内被称为局部变量。然后存储两个函数,每个函数都引用另一个变量。

    【讨论】:

    • 好的,谢谢。我设法自己弄清楚了,但这个答案仍然很有用。
    【解决方案2】:

    您可以通过在声明实际函数体之前声明其名称来转发声明函数:

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

    但是,只有在声明具有本地范围的函数时才需要前向声明。这通常是你想要做的,但 Lua 也支持更像 C 的语法,在这种情况下不需要前向声明:

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

    【讨论】:

    • 实际上,您的第一个示例并没有像您认为的那样做,因为第二个 local func1 声明了一个具有该名称的 new 变量并留下了第一个 func1孤立并仍设置为nil
    • 您的第二个示例也很糟糕,因为从 func1 下方天真地调用“func2”会起作用,但不是因为任何类型的“前向声明”。相反,func1 是在全局环境 (_G) 中声明的,当 func2 查找 func1 时,它会检查 _G。这意味着 func1 是在 func2 运行之前声明的,因此当它检查 _G 时,它可以工作。在 func2 定义后立即抛出 func2 调用会导致错误...因为 func1 未声明/定义。
    • 这就是为什么我说“但是只有在声明具有本地范围的函数时才需要前向声明”。换句话说,我明确表示第二个示例不使用前向声明。
    【解决方案3】:

    在Freeswitch内嵌lua下测试,前向声明不起作用:

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

    结果:

    [ERR] mod_lua.cpp:203 /usr/local/freeswitch/scripts/foo.lua:1: 尝试调用全局“fmsg”(一个零值)

    颠倒顺序确实(duh)有效。

    【讨论】:

      【解决方案4】:

      要了解 Lua 中的前向引用与 C 相比如何工作,您必须了解 C 编译和 Lua 执行之间的根本区别。

      • 在 C 中,前向引用是一种编译时 机制。因此,如果您在 C 模块中包含前向声明模板,那么您后面的任何代码都将在编译调用时使用此模板。您可能会或可能不会在同一个模块中包含函数实现,在这种情况下,两个声明必须在语义上相同,否则编译器会出错。由于这是一个编译时构造,因此编译后的代码可以按任意顺序执行。

      • 在 Lua 中,前向引用是 runtime 机制,因为编译后的函数会在代码内部生成函数原型,但这只能作为运行时 Lua 变量或值在执行有 传递了创建 Lua closure 的声明。这里源中的声明顺序无关紧要。重要的是执行顺序:如果闭包尚未绑定到变量,则执行抛出“nil value”异常。
        如果您使用的是本地变量来保存函数值,那么正常的局部作用域规则仍然适用:local 声明必须先于它在源中的使用并且必须在作用域内,否则编译器将编译错误的全局或外部局部引用。因此,在其他答案中讨论的使用本地变量的前向引用将起作用,但前提是 Protos 在执行第一次调用之前绑定到闭包

      【讨论】:

        【解决方案5】:

        如果我尝试在定义之前调用该函数,则对我不起作用。我在 nginx conf 中使用这个 Lua 脚本。

        lua 入口线程中止:运行时错误:lua_redirect.lua:109:尝试调用全局 'throwErrorIfAny'(一个 nil 值)

        代码sn-p -

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

        鉴于其他一些答案也指出它也不适用于他们,Lua 的前向声明可能不适用于其他工具。

        PS:如果我把函数定义放在之前,然后在病房之后调用它就可以了。

        【讨论】:

          【解决方案6】:

          如果您使用 OOP,您可以在其“定义”之前调用任何函数成员。

          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
          

          【讨论】:

            猜你喜欢
            • 2017-05-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-10-29
            • 2014-02-10
            • 1970-01-01
            • 2014-10-01
            • 2011-11-28
            相关资源
            最近更新 更多