&引用;“主要”;Lua中的函数?
在python中,通常会定义一个主函数,以便将脚本用作模块(如果需要): 在Lua中,习惯用法&引用;“主要”;Lua中的函数?,lua,Lua,在python中,通常会定义一个主函数,以便将脚本用作模块(如果需要): 在Lua中,习惯用法if\uuuuu name\uuuuu==“\uuuu main\uuuuuu”本身是不可能的(这意味着,我认为不可能) 为了在Lua中有类似的行为,我通常会这么做: os.exit((function(args) print("Hello world") return 0 end)(arg)) 。。。但这种方法似乎“过于夸张”:-) 是否有更常见的方法(除了定义一个全局主函数,这似乎
if\uuuuu name\uuuuu==“\uuuu main\uuuuuu”
本身是不可能的(这意味着,我认为不可能)
为了在Lua中有类似的行为,我通常会这么做:
os.exit((function(args)
print("Hello world")
return 0
end)(arg))
。。。但这种方法似乎“过于夸张”:-)
是否有更常见的方法(除了定义一个全局主函数,这似乎是多余的)?您可以尝试检查是否需要该模块 从文件: package.loaded由require使用的表 要控制哪些模块已安装,请执行以下操作: 加载。当您需要模块时 modname和package.loaded[modname]为 不为false,require只返回 存储在那里的值 有了这个,你可以写:
if not package.loaded['modulename'] then
main()
end
没有“适当”的方法来做到这一点,因为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:~$
它通过检查堆栈深度是否大于3(stock Lua解释器中文件的正常深度)来工作。但是,此测试可能会在Lua版本之间中断,甚至在任何嵌入式/自定义Lua构建中也会中断
我还将包括这个(稍微更便携的)替代方案,尽管它在启发式方面有了更大的飞跃,并且有一个失败案例(见下文):
这个函数通过比较_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
当Lua
require
s一个模块时,它会以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
的第一个参数调用脚本,或者使用其他已加载模块的名称),但可能已经足够好了。在其他情况下,我遵从MattJ的回答
if arg ~= nil and arg[0] == string.sub(debug.getinfo(1,'S').source,2) then
print "Main file"
else
print "Library"
end
解释:
arg
表从解释器调用脚本,其中arg[0]
是脚本的名称debug.getinfo
函数返回一个信息表,该表描述了由编号参数给定的堆栈级别上的函数(1表示调用getinfo
的函数;0表示getinfo
本身)。它的第二个参数是可选的:它指定要检索的getinfo字段的子集。“S”定义源名称getinfo
返回的表的source
字段包含函数在其中定义的文件名,前缀为@
。通过将该字段的值传递给string.sub(…,2)
,我们可以剥离该@
。(short\u src
字段包含不带@
的名称,但这是因为它被定义为“打印友好”名称,并且比剥离源代码更不安全)
请注意,此代码使用了一个
debug
函数,因此在5.2中,您必须要求debug
才能使用它。这有什么问题:
$ cat aa.lua
#!/usr/bin/lua
if (arg ~= nil and arg[-1] ~= nil) then
print "main"
else
print "library"
end
$ ./aa.lua
main
$ ./aa.lua arg1 arg2
main
$ cat bb.lua
#!/usr/bin/lua
print("in bb")
$ lua -laa bb.lua
library
in bb
$ lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> require "aa"
library
>
也许您可以使用debug.getinfo()函数处理调试库
if debug.getinfo(1).what == "main" then
-- Main execution
end
有关更多信息,请参阅参考手册。我将建议另一种变体,它似乎适用于lua5.1和lua5.2:
function is_main(offset)
return debug.getinfo(4 + (offset or 0)) == nil
end
if is_main() then
print("Main chunk!")
else
print("Library chunk!")
end
如果您不想为此定义一个额外的函数is\u main
,您可以执行以下操作:
if debug.getinfo(3) == nil then
print("Main chunk!")
else
print("Library chunk!")
end
我正在使用Lua5.3,这里的大多数建议都有问题。这就是我的用例的工作原理:
local my_module = {}
...
if os.getenv('CLI') then
main()
else
return my_module
end
从命令行运行时,我简单地定义了环境变量,例如:
CLI=1 lua my_script.lua
为我工作™ 缺点是,您必须知道模块的名称
arg[0]
也不起作用,因为lua模块在之后匹配。lua;?。BIN
(BIN是本机库的文件扩展名,例如.so或.dll)您试图实现什么?我假设您希望将此代码放入自己的模块中,并知道如何命名。顺便说一句,arg[0]返回正在运行或需要您的模块的lua文件的名称。try:test1.lua>require“test”test.lua>print(arg[0])“顺便说一句,arg[0]返回正在运行的lua文件的名称”-我在前面的评论中已经提到过…这在lua5.2中不起作用。只有当模块返回时,package.loaded
条目才会被插入。我希望我可以多次向上投票:-)。我想我现在会坚持使用getfenv
方法,因为它看起来更小。我一定会记住另一个解决方案。@coldfix我添加了一些似乎适用于5.2的修改代码。不过,我的其余答案仍然有效,使用风险自负:)这看起来不错,而且比第二种方法更干净/更不容易出错。相应的范围是否保证至少有一个条目?我发布了一个非常类似的解决方案,使用debug.getinfo
而不是debug.getlocal
,它使用了pcall
local my_module = {}
...
if os.getenv('CLI') then
main()
else
return my_module
end
CLI=1 lua my_script.lua