Lua中的“main”函数?

2024-05-19 02:24:56 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

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

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

我通常就是这样做的,以便在Lua有类似的行为:

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

。。。但这种方法似乎相当“重括号”:-)

有没有更常见的方法(除了定义一个全局主函数之外,它似乎是多余的)?


Tags: 模块方法函数name脚本helloworldreturn
3条回答

没有“正确”的方法来做这件事,因为Lua并没有真正区分代码的来源,它们都只是函数。也就是说,这至少在Lua5.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(stock Lua解释器中文件的正常深度)来工作。但是,这个测试可能会在Lua版本之间中断,甚至在任何嵌入式/自定义Lua构建中也是如此。

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

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个参数执行主脚本时,这是模块的确切名称:

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
> 

鉴于以上情况,我希望至少你知道你的立场,即使这不是你所想的:)

更新:对于在lua 5.1和5.2中工作的hybrid.lua版本,可以用debug.getlocal替换getfenv:

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

您可以尝试检查是否需要该模块。

来自文档:

package.loaded A table used by require to control which modules are already loaded. When you require a module modname and package.loaded[modname] is not false, require simply returns the value stored there.

有了这个你可以写:

if not package.loaded['modulename'] then
    main()
end

当Lua require是一个模块时,它会将它的名称作为varargs(...)传递给它。

因此,如果脚本不打算接受任何参数(从命令行或其他方式),可以使用

if ... then
  return this_mod --module case
else
  main() --main case
end

不过,请注意,在(完全)可能的情况下,这并不是万无一失的。不过,在这一点上,你可以结合卢卡斯的回答得到:

if not package.loaded[...] then
  --main case
else --module case
end

仍然不是完美的(例如,如果使用string的第一个参数或其他已加载模块的名称调用脚本),但可能已经足够好了。在其他情况下,我听从马蒂的回答。

相关问题 更多 >

    热门问题