在Lua中转发定义一个函数?

发布于 2024-11-08 13:45:45 字数 65 浏览 0 评论 0原文

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

How do I call a function that needs to be called from above its creation? I read something about forward declarations, but Google isn't being helpful in this case. What is the correct syntax for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

情感失落者 2024-11-15 13:45:45

Lua 是一种动态语言,函数只是一种可以使用 () 运算符调用的值。因此,您实际上并不需要向前声明该函数,只需确保调用该函数时作用域中的变量是您认为的变量即可。

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

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

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

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

Lua is a dynamic language and functions are just a kind of value that can be called with the () operator. So you don't really need to forward declare the function so much as make sure that the variable in scope when you call it is the variable you think it is.

This is not an issue at all for global variables containing functions, since the global environment is the default place to look to resolve a variable name. For local functions, however, you need to make sure the local variable is already in scope at the lexical point where you need to call the value it stores, and also make sure that at run time it is really holding a value that can be called.

For example, here is a pair of mutually recursive local functions:

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

Of course, that is also an example of using tail calls to allow infinite recursion that does nothing, but the point here is the declarations. By declaring the variables with local before either has a function stored in it, those names are known to be local variables in lexical scope of the rest of the example. Then the two functions are stored, each referring to the other variable.

乖乖公主 2024-11-15 13:45:45

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

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

但是,只有在声明具有局部作用域的函数时才需要向前声明。这通常是您想要做的,但是 Lua 也支持更像 C 的语法,在这种情况下不需要前向声明:

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

You can forward declare a function by declaring its name before declaring the actual function body:

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

However forward declarations are only necessary when declaring functions with local scope. That is generally what you want to do, but Lua also supports a syntax more like C, in which case forward declaration is not necessary:

function func2()
  func1()
end
function func1()
  --do something
end
柠北森屋 2024-11-15 13:45:45

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

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

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

To comprehend how forward referencing in Lua works compared to C, you must understand the a fundamental difference between C compilation and the Lua execution.

  • In C, forward referencing is a compile time mechanism. Hence if you include a forward declaration template in a C module then any of your code following will employ this template in compiling the call. You may or may not include the function implementation in the same module, in which case both declarations must be semantically identical or the compiler will error. Since this is a compile time construct, the compiled code can be executed in any order.

  • In Lua, forward referencing is runtime mechanism, in that the compiled function generates a function prototype internally within the code, but this is only accessible as a runtime Lua variable or value after the execution has
    passed over the declaration creating a Lua closure. Here the declaration order within the source is immaterial. It is the execution order that is important: if the closure hasn't been bound to the variable yet, then the execution will throw a "nil value" exception.
    If you are using a local variable to hold the function value, then normal local scoping rules still apply: the local declaration must precede its use in the source and must be within scope, otherwise the compiler will compile in the wrong global or outer local reference. So forward referencing using locals as discussed in other answer will work, but only if the Protos are bound to closures before the first call is executed.

甚是思念 2024-11-15 13:45:45

在 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: attempts to call global 'fmsg' (a nil value )

颠倒顺序确实(废话)有效。

Testing under the embedded lua in Freeswitch, forward declaration does not work:

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

result:

[ERR] mod_lua.cpp:203 /usr/local/freeswitch/scripts/foo.lua:1: attempt to call global 'fmsg' (a nil value)

Reversing the order does (duh) work.

谁的年少不轻狂 2024-11-15 13:45:45

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

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

代码片段-

...
throwErrorIfAny()
...

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

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

PS:如果我把函数定义放在前面然后在后面调用它,效果就很好。

Doesn't work for me if I try to call the function before definition. I am using this Lua script in nginx conf.

lua entry thread aborted: runtime error: lua_redirect.lua:109: attempt to call global 'throwErrorIfAny' (a nil value)

Code snippet -

...
throwErrorIfAny()
...

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

Given some other answers have also pointed out that it didn't work for them either, it is possible that forward declaration of Lua doesn't work with other tools.

PS : It works fine if I put the function definition before and then call it after wards.

任性一次 2024-11-15 13:45:45

如果您使用 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

If you use OOP you can call any function member prior its "definition".

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()

Program output:

f1
later
f2
later
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文