没有“正确”的方法来做到这一点,因为 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(普通 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
>
鉴于上述内容,我希望至少您知道自己的立场,即使这并不完全是您的想法:)
Update:对于适用于 Lua 5.1 和 5.2 的 Hybrid.lua 版本,您可以将 getfenv 替换为 debug.getlocal:
if pcall(debug.getlocal, 4, 1) then
print("Library")
else
print("Main file")
end