22 lua
在python中,通常会定义一个main函数,以便允许脚本用作模块(如果需要):
def main():
print("Hello world")
return 0
if __name__ == "__main__":
sys.exit(main())
Run Code Online (Sandbox Code Playgroud)
在Lua中,这样的成语if __name__ == "__main__"是不可能的(这意味着,我认为不是这样).
这就是我为了在Lua中有类似行为而通常所做的事情:
os.exit((function(args)
print("Hello world")
return 0
end)(arg))
Run Code Online (Sandbox Code Playgroud)
......但这种方法似乎相当"重要的括号":-)
是否有更常见的方法(除了定义一个看似多余的全局主函数)?
Mat*_*ttJ 13
没有"正确"的方法来做到这一点,因为Lua并没有真正区分代码来自哪里,它们都只是函数.也就是说,这至少似乎在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:~$
Run Code Online (Sandbox Code Playgroud)
它的工作原理是检查堆栈深度是否大于3(库存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
>
Run Code Online (Sandbox Code Playgroud)
这个通过比较_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
>
Run Code Online (Sandbox Code Playgroud)
鉴于上述情况,我希望至少你知道你的立场,即使它不是你想到的:)
更新:对于在Lua 5.1和5.2中运行的hybrid.lua版本,可以使用debug.getlocal替换getfenv:
if pcall(debug.getlocal, 4, 1) then
print("Library")
else
print("Main file")
end
Run Code Online (Sandbox Code Playgroud)
当Lua requiresa模块时,它将它require与varargs(...)一起传递给它.
因此,如果您的脚本不打算采用任何参数(从命令行或其他方式),您可以使用类似的东西
if ... then
return this_mod --module case
else
main() --main case
end
Run Code Online (Sandbox Code Playgroud)
但是,请注意,在您采用参数的(完全)可能的情况下,这并非万无一失.但是,在这一点上,你可以将它与Lukasz的答案结合起来得到:
if not package.loaded[...] then
--main case
else --module case
end
Run Code Online (Sandbox Code Playgroud)
仍然不完美(例如,如果使用第一个参数string或其他已经加载的模块的名称调用脚本),但可能已经足够好了.在其他情况下,我会按照MattJ的回答.
您可以尝试检查是否需要该模块.
来自文件:
package.loaded require用来控制已加载哪些模块的表.当您需要模块modname且package.loaded [modname]不为false时,require只返回存储在那里的值.
有了这个你可以写:
if not package.loaded['modulename'] then
main()
end
Run Code Online (Sandbox Code Playgroud)