Lua:制作模块系统
Posted
技术标签:
【中文标题】Lua:制作模块系统【英文标题】:Lua: make module system 【发布时间】:2013-04-04 15:15:24 【问题描述】:我想创建一个在不同文件夹中有多个模块的程序。主程序将确定需要加载哪个模块并将其加载。除此之外它还会加载一些核心功能。
我创建了这个逻辑的原型,效果很好。 但由于我是 Lua 的新手,我不确定实现此功能的正确方法。
现在我有下一个文件结构:
aoc(主程序):
aoc =
aoc_base_path = debug.getinfo(1).source:match("@(.*)/.*$") -- base path to my program
if not aoc_base_path then
aoc_base_path = ''
else
aoc_base_path = aoc_base_path..'/'
end
local aoc_base_arg=...
dofile(aoc_base_path.."core/core")
local module = assert(loadfile(aoc_base_path.."modules/"..aoc_base_arg[1].."/module"))
local arg = table.copy(aoc_base_arg) -- this is my custom function (I'm not provide you with listing, it just copy one table to another one
table.remove(arg,1)
module(arg,aoc) -- pass to module all arguments except first one
core/core(核心函数加载器):
dofile (aoc_base_path..'core/move')
核心/移动:
local function move(direction, refuel, dig, attack)
-- some logic in local function (to not be overwriten in module)
end
function aoc.move()
-- global function (it logic can be changed by module in case it needed)
return move()
end
modules/mine/module(模块):
local arg=... -- I passed 2 arguments in aoc main program
arg = arg[1]
local aoc = arg[2]
aoc.move()
暂时
lua> aoc 我的
或
lua> path/to/aoc mine
工作正常。但是,如果我做错了什么,谁能指出我?
编辑:通过获取aoc_base_path
改变逻辑
【问题讨论】:
您可能还想稍微调整一下 package_path 。也许这样会更好。 @BartekBanachewicz 如果您的意思是与debug.getinfo(1).source:match("@(.*)/.*$")
一致,这只是一个示例。实际上,我以某种不同的方式获得了这条路径(我的程序是一些游戏的模组,它为我提供了shell.getRunningProgram()
功能)。
是错字吗:match("@(.*)/.*$")
?可能,提到了match'^(.*)/'
?也可以写成match'(.*)/'
。
@EgorSkriptunoff nope:echo 'print(debug.getinfo(1).source)' > test; lua test
给了@test
@ArthurHalma - 感谢您提供信息。以前从未使用过此功能。
【参考方案1】:
你可以稍微简化一下aoc:
aoc =
aoc_base_path = debug.getinfo(1).source:match("@(.*/)") or ''
dofile(aoc_base_path.."core/core")
local module = assert(loadfile(aoc_base_path.."modules/".. ... .."/module"))
module(select(2,...),aoc)
【讨论】:
谢谢,但你能解释一下"modules/".. ... .."/module"
的三个点是什么意思吗(我玩 Lua 不到 24 小时)?我认为当 aoc 获得超过 1 个参数时会出错。
@ArthurHalma - 如果在另一个表达式中使用 vararg 表达式,则将其调整为一个元素。【参考方案2】:
只需使用 Lua 的库内置模块功能和 require
。通过正确设置package.loaders
,您可以配置此标准系统以从您想要的任何地方以任何您想要的方式加载模块。特定目录,直接来自 HTTP,由鸽子根据 RFC 1149 交付 - 它可以完成所有工作。
【讨论】:
这种方法有什么好处? 它是标准的、内置的和可扩展的。你还需要什么? 看起来这是我需要的;)。我的文件结构怎么样,我可以保持现在这样吗? @ArthurHalma,绝对。默认情况下,模块名称中的点会转换为文件系统中的子目录。【参考方案3】:要保持目录结构或多或少相同,但要使用 lua 包系统,您可以使用如下方法:
在你的基本路径中有一个文件aoc.lua
:
local aoc =
local module = ...
local dir = module:gsub("%.","%/"):sub(1,-4)
package.path = dir.."?.lua;"..package.path
package.path = dir.."?/init.lua;"..package.path
package.path = dir.."modules/?.lua;"..package.path
return aoc
在 /core 中有一个文件 init.lua
require
s 您要包含的核心包
require"core.move"
然后您的核心包将如下所示:
local function move(direction, refuel, dig, attack)
-- some logic in local function (to not be overwriten in module)
end
require"aoc".move = move
在 /modules 中,您可以通过为每个模块创建一个 lua 文件来使事情变得更简单,因此 /modules/mine.lua 看起来像:
local aoc = require"aoc"
aoc.move()
然后在 lua 提示符下你会写:
lua> 需要“path.to.aoc”
lua> require"core" --加载核心模块
lua> require"mine" -- 加载我的
编辑
如果你想保持相同的风格,将aoc.lua更改为return
并添加一个文件aoc,如下所示:
local dir = debug.getinfo(1).source:match("@(.*)/.*$") -- base path to my program
if not dir then dir = ''
else dir = dir..'/'
end
package.path = dir.."?.lua;"..package.path
package.path = dir.."?/init.lua;"..package.path
package.path = dir.."modules/?.lua;"..package.path
require"core"
for _,mod in ipairs... do
require(mod)
end
我建议这种方法的优点是所有的修改都在一个文件中,在这种情况下是 aoc,文件结构的其余部分使用相当标准的 lua 包约定。
【讨论】:
再也没有机会以path/to/aoc mine
的身份执行我的程序了吗?
看来我无权访问package
。因为我为一个游戏做了一个插件,所以我有一个有限的 lua。所以你的代码package.path = dir.."?.lua;"..package.path
返回attemp to index ? (a nil value)
错误。以上是关于Lua:制作模块系统的主要内容,如果未能解决你的问题,请参考以下文章
一个使用 xmake 构建 c/c++ 模块的 luarocks 插件