“主要"Lua 中的函数? [英] "main" function in Lua?

查看:14
本文介绍了“主要"Lua 中的函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 python 中,通常会定义一个 main 函数,以允许将脚本用作模块(如果需要):

In python, one would usually define a main function, in order to allow the script to be used as module (if needed):

def main():
    print("Hello world")
    return 0

if __name__ == "__main__":
    sys.exit(main())

在 Lua 中,习语 if __name__ == "__main__" 是不可能的(这意味着,我认为不可能).

In Lua, the idiom if __name__ == "__main__" isn't possible as such (that means, I don't think it is).

为了在 Lua 中有类似的行为,我通常会这样做:

That's what I'm usually doing in order to have a similar behaviour in Lua:

os.exit((function(args)
    print("Hello world")
    return 0
end)(arg))

...但这种方法似乎在括号上很重":-)

... But this approach seems rather "heavy on parentheses" :-)

有没有更通用的方法(除了定义一个全局的 main 函数,看起来是多余的)?

Is there a more common approach (besides defining a global main function, which seems redundant)?

推荐答案

没有正确"的方法可以做到这一点,因为 Lua 并没有真正区分代码的来源,它们都只是函数.也就是说,这至少在 Lua 5.1 中似乎有效:

There's no "proper" way to do this, since Lua doesn't really distinguish code by where it came from, they are all just functions. That said, this at least seems to work in Lua 5.1:

matthew@silver:~$ cat hybrid.lua 
if pcall(getfenv, 4) then
    print("Library")
else
    print("Main file")
end
matthew@silver:~$ lua hybrid.lua 
Main file
matthew@silver:~$ lua -lhybrid
Library
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> ^C
matthew@silver:~$ lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> require "hybrid"
Library
> ^C
matthew@silver:~$

它的工作原理是检查堆栈深度是否大于 3(普通 Lua 解释器中文件的正常深度).不过,此测试可能会在 Lua 版本之间中断,甚至在任何嵌入式/自定义 Lua 版本中也可能会中断.

It works by checking whether the stack depth is greater than 3 (the normal depth for a file in the stock Lua interpreter). This test may break between Lua versions though, and even in any embedded/custom Lua builds.

我还将包括这个(稍微更便携)的替代方案,尽管它在启发式方面取得了更大的飞跃,并且有一个失败案例(见下文):

I'll also include this (slightly more portable) alternative, although it's taking an even greater leap in heuristics, and has a failure case (see below):

matthew@silver:~$ cat hybrid2.lua 
function is_main(_arg, ...)
    local n_arg = _arg and #_arg or 0;
    if n_arg == select("#", ...) then
        for i=1,n_arg do
            if _arg[i] ~= select(i, ...) then
                print(_arg[i], "does not match", (select(i, ...)))
                return false;
            end
        end
        return true;
    end
    return false;
end

if is_main(arg, ...) then
    print("Main file");
else
    print("Library");
end
matthew@silver:~$ lua hybrid2.lua 
Main file
matthew@silver:~$ lua -lhybrid2
Library
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> ^C
matthew@silver:~$ lua 
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> require "hybrid2"
Library
>

这个是通过比较 _G.arg 的内容和 '...' 的内容来工作的.在主块中,它们将始终相同.在模块中 _G.arg 仍将包含命令行参数,但 '...' 将包含传递给 require() 的模块名称.鉴于您知道模块名称,我怀疑这对您来说更接近于更好的解决方案.此代码中的错误在于用户使用 1 个参数执行主脚本时,这是您的模块的确切名称:

This one works by comparing the contents of _G.arg with the contents of '...'. In the main chunk they will always be the same. In a module _G.arg will still contain the command-line arguments, but '...' will contain the module name passed to require(). I suspect this is closer to the better solution for you, given that you know your module name. The bug in this code lies when the user executes the main script with 1 argument, and this is the exact name of your module:

matthew@silver:~$ lua -i hybrid2.lua hybrid2
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
Main file
> require "hybrid2"
Main file
> 

鉴于以上内容,我希望您至少知道自己的立场,即使这与您的想法不完全相同:)

Given the above I hope at least you know where you stand, even if it isn't exactly what you had in mind :)

更新:对于适用于 Lua 5.1 和 5.2 的 hybrid.lua 版本,您可以将 getfenv 替换为 debug.getlocal:

Update: For a version of hybrid.lua that works in Lua 5.1 and 5.2, you can replace getfenv with debug.getlocal:

if pcall(debug.getlocal, 4, 1) then
    print("Library")
else
    print("Main file")
end

这篇关于“主要"Lua 中的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆