Module 如何在Lua中构造一个自包含的模块?

Module 如何在Lua中构造一个自包含的模块?,module,lua,require,Module,Lua,Require,我正在为Love2D制作一个Lua库,其中包含相当多的内部子模块、类文件等 我现在所做的看起来是这样的: 文件./libname/init.lua 文件./libname/types/Blah.lua 这里的问题是lib是一个全局的,如果我把它变成一个局部的,我就不能正确地构造像Blah这样的子模块,因为它们不再能够访问lib表 这显然是一个简化的示例,但我认为它很好地说明了我的问题-我希望将lib表设置为本地,并返回它,这样库的包含方式就像lib=require libs.libname一样,

我正在为Love2D制作一个Lua库,其中包含相当多的内部子模块、类文件等

我现在所做的看起来是这样的:

文件./libname/init.lua 文件./libname/types/Blah.lua 这里的问题是lib是一个全局的,如果我把它变成一个局部的,我就不能正确地构造像Blah这样的子模块,因为它们不再能够访问lib表

这显然是一个简化的示例,但我认为它很好地说明了我的问题-我希望将lib表设置为本地,并返回它,这样库的包含方式就像lib=require libs.libname一样,而不是在需要模块本身时将整个内容导入全局范围。有可能吗?

让我们看看相关的:

需要modname [……]

一旦找到加载程序,require将使用两个参数调用加载程序:modname和一个额外的值,具体取决于它如何获得加载程序。如果加载程序来自文件,则此额外值是文件名。如果加载程序返回任何非nil值,require会将返回的值分配给package.loaded[modname]。如果加载程序未返回非nil值,并且未向package.loaded[modname]分配任何值,则require会将true分配给此条目。在任何情况下,require都会返回package.loaded[modname]的最终值

因此,对于具有此类递归依赖关系的模块,方法是:

获取模块名modname第一个未命名的var arg参数 加载基本初始化所需的模块 如果模块已在2递归调用中完全设置,则返回 在package.loaded[modname]下设置模块表 设置足够的脚手架以启动子模块 需要子模块 完成其余模块的设置。 Return由于步骤4,不需要返回任何内容。 这允许您根本不创建任何全局变量,这对于现代模块来说是合适的

如果在设置主模块时不需要任何子模块,则考虑使用按需加载代替:

setmetatable(_M, {__index =
  function(t, k)
    t[k] = require(modname.."."..k)
    return t[k]
  end})
如果您的模块只被构造成子模块供外部使用,您可以将其全部放在主模块中,让它自己将适当的成员表注册为子模块,请参见步骤2。
在这种情况下,子模块加载程序只需要主模块,不返回任何内容。

我为这个概念做了一个指南。你可以在这里找到它:

为了解决您在问题中提到的具体问题,我将使用3个文件:core.lua来共享状态,更改core的真实文件,以及init来绑定所有内容

./libname/core.lua是定义lib的地方,作为本地条。它不定义lib.types。它为其他文件可能希望使用的实用程序奠定了基础,例如设置前缀或实用程序类

像./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

评论中提到的当前文件夹技巧如下:

我明白了,这很有帮助,我现在知道到哪里去找了。您是否有或可以编写一些简单的示例来说明如何执行上述步骤?我不想这么说,但从你的回答或文档中我真的没有任何线索。添加了示例,步骤1到5有一行,步骤6没有。我假设我把代码放在init.lua中作为我的模块目录,对吗?另外,我主要使用Love2D,我假设它为我做了一些设置,我发现仅使用Lua,我就必须将./?/init.Lua添加到我的package.path中。我假设在这个设置中,我将在子模块中执行require module.required_子模块,对吗?还可以。。。请原谅评论/问题计数,在这种情况下,我将如何处理相关需求?比如说,我可以从另一个子模块中要求src.module.required_子模块,但是如果我想让模块的工作方式独立于它的目录是放在src还是lib中,还是放在该_dumb_模块中呢?@Asmageddon:看,你可以使用它,只需要一个替换就可以使用正确的模式和选项,从模块名称中删除任意数量的子模块说明符,并用您想要的任何内容替换它们。看起来是一个很好的指南,但我看不出它解决了我的问题—让相互依赖的子模块访问主模块表而不将其放入全局表中。比如说,我可以将lib.mymodule.submodule.a剥离到lib.mymodule,但我必须调整每个文件所需的代码,或者至少在涉及更深层的fs层次结构时调整其深度,这是我不想做的。我最终只是将模块表放入包中。加载[\uu mymodule]并在内部要求它。我不能说我喜欢这个解决方案,但似乎没有其他好的替代方案,或者至少到目前为止,我还没有看到任何替代方案。同样地,重复数据消除程序也没有向我提供任何他所提到的如何解决我的问题的例子,你的好文章也没有
跳舞,而不是解决你的具体问题。我已经用解决你问题的方法更新了我的答案。嗯,这看起来不错,但我真的不想在每个文件中使用当前的文件夹技巧,因为它意味着层次结构中至少每个不同深度都有一行不同的内容,每当我移动文件时都必须更新。我真的很喜欢您的解决方案+将模块表放入包中的想法。。。我只是不知道这是否是一个好的解决方案,因为我有时会有巨大的焦虑问题,感觉有点不舒服。我的意思是,不太可能有人会创建一个名为_mymodule/__的模块,但是……也许我只是想得太多了:/
setmetatable(_M, {__index =
  function(t, k)
    t[k] = require(modname.."."..k)
    return t[k]
  end})
local lib = {}

lib.prefix = (...):match("(.-)[^%.]+$") .. "libname."

lib.class = require(lib.prefix .. "lib.class")

return lib
local lib = require 'core' -- or libname.core or using the current_folder trick

local Blah = lib.class()
...
return Blah
local lib = require 'core' -- or libname.core or current_folder trick

lib.types.Blah = require(lib.prefix .. "types.Blah")

return lib