这是一个与此处给出的答案相关的小问题,https://tex.stackexchange.com/a/201742/17858计算外部 lua 文件中数字的阶乘。
\documentclass{article}
%\directlua{dofile("luatest.lua")}
\directlua{require("luatest.lua")}
\newcommand*{\myluafact}[1]{%
\directlua{tex.write(fact(#1))}%
}
\begin{document}
test \myluafact{5}
\end{document}
计算阶乘的代码luatest.lua
同样是从上面同一个链接复制而来的
function fact (n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end
对于这个特定示例,在我的计算机上使用dofile
和得到的结果相同。require
require
使用或dofile
一般情况下加载外部 lua 文件是否存在技术差异?
答案1
总结 require
被缓存了,dofile
不是吗。
与 相比dofile
,require
缓存已请求过的文件。例如,如果您加载模块,example
local example = require("example")
Lua 会把从 返回的句柄添加example
到名为 的内部表中package.loaded
。如果您的应用程序require("example")
再次调用,Lua 将不会example
再次加载该模块,而只是返回缓存在 中的句柄package.loaded
。
这种方法还表明了为什么在应该用作模块的文件中定义全局变量是个坏主意。luatest
问题中的模块只定义全局名称fact
,但不返回句柄。因此,Lua 解释器无法缓存它,如果重新定义了全局名称,fact
则无法恢复原始名称。全局名称的另一个问题是,它们往往会发生冲突。想象一下,您有第二个模块也定义了fact
全局名称。Lua 应该采用哪一个?
原则上,你可以将dofile
模块用于只加载一次且其中定义的所有名称不太可能发生冲突的文件。就我个人而言,即使是在这种情况下,我也更喜欢模块,因为它可以减少相互依赖性并使内容在其他上下文中可重复使用。
您应该重构您的示例:
luatest.lua
local function fact(n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end
return { fact = fact }
test.tex
\documentclass{article}
\directlua{luatest = require("luatest")}
\newcommand*{\myluafact}[1]{%
\directlua{tex.write(luatest.fact(#1))}%
}
\begin{document}
test \myluafact{5}
\end{document}