我正在为Love2D创建一个Lua库,其中包含相当多的内部子模块,类文件等。
我现在正在做的事情如下:
档案./libname/init.lua
lib.prefix = (...):match("(.-)[^%.]+$") .. "libname."
lib = {}
lib.class = require(lib.prefix .. "lib.class")
lib.types.Blah = require(lib.prefix .. "types.Blah")
return lib
档案./libname/types/Blah.lua
local Blah = lib.class()
...
return Blah
除了这里的东西是lib是一个全局的,如果我把它变成一个本地,我无法正确构建像Blah
这样的子模块,因为它们不再能够访问lib
表
这显然是一个被剥离的示例,但我认为它很好地证明了我的问题 - 我想将lib
表本地化,然后返回它,以便包含库就像{{1}当我需要模块本身时,而不是将整个事物导入全局范围。有可能吗?
答案 0 :(得分:3)
我为这个概念做了一个指南。你可以在这里找到它:
http://kiki.to/blog/2014/03/30/a-guide-to-authoring-lua-modules/
要解决您在问题中提到的具体问题,我会使用3个文件:core.lua
来分享状态,更改核心的“真实文件”以及init
来绑定所有内容起来。
./libname/core.lua
是定义lib
的地方,作为本地栏。它没有定义lib.types
。它使用其他文件可能想要使用的实用程序“设置”,例如设置前缀或实用程序class
。
local lib = {}
lib.prefix = (...):match("(.-)[^%.]+$") .. "libname."
lib.class = require(lib.prefix .. "lib.class")
return lib
“常规文件”(如./libname/types/Blah.lua
)使用这些实用程序,但根本不修改lib:
local lib = require 'core' -- or libname.core or using the current_folder trick
local Blah = lib.class()
...
return Blah
init.lua
将所有内容绑定在一起:
local lib = require 'core' -- or libname.core or current_folder trick
lib.types.Blah = require(lib.prefix .. "types.Blah")
return lib
评论中提到的“当前文件夹技巧”在这里:http://kiki.to/blog/2014/04/12/rule-5-beware-of-multiple-files/#the-current_folder-trick
答案 1 :(得分:1)
让我们采取相关的paragraph from the documentation:
require(modname)
[...]
找到加载器后,
require
使用两个参数调用加载器:modname
和一个额外的值,取决于它如何获取加载器。 (如果加载器来自文件,则此额外值是文件名。)如果加载器返回任何非零值,则需要将返回值分配给package.loaded[modname]
。如果加载器未返回非零值且未向package.loaded[modname]
分配任何值,则require将为此条目指定true。在任何情况下,require都会返回package.loaded[modname]
的最终值。
因此,具有这种递归依赖性的模块的方法是:
modname
(第一个未命名的var-arg参数)package.loaded[modname]
require
子模块local _M, modname = {}, {...}[1]
local sub = require(modname..".sub")
if package.loaded[modname] then return end
package.loaded[modname] = _M
-- Populate _M with everything needed to set up more modules
_M.X = require(modname..".X")
--Do the rest of this modules setup and that's it
--return
这允许你根本不创建任何全局变量,正如现代模块所适用的那样。
如果在设置主模块时不需要任何子模块,请考虑使用按需加载:
setmetatable(_M, {__index =
function(t, k)
t[k] = require(modname.."."..k)
return t[k]
end})
如果您的模块只能构建为子模块以供外部使用,您可以将其全部放在主模块中,并让它将相应的成员表作为子模块注册(参见步骤2)。 />
在这种情况下,子模块加载器只会require
主模块并且不返回任何内容。