LuaLatex:加载lua文件时`dofile`和`require`的区别

LuaLatex:加载lua文件时`dofile`和`require`的区别

这是一个与此处给出的答案相关的小问题,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不是吗。


与 相比dofilerequire缓存已请求过的文件。例如,如果您加载模块,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}

相关内容