按相对路径加载Lua文件

58

如果我的文件结构像这样:

./main.lua
./mylib/mylib.lua
./mylib/mylib-utils.lua
./mylib/mylib-helpers.lua
./mylib/mylib-other-stuff.lua

main.lua 中可以使用完整路径 require('mylib.mylib') 加载文件 mylib.lua。但是在 mylib.lua 内部,我还想加载其他必要的模块,而且不想总是指定完整路径(例如 mylib.mylib-utils)。如果我决定移动文件夹,那么就需要进行大量的查找和替换。是否有一种方法只使用相对路径呢?

UPD. 我正在使用 Corona SDK 的 Lua,如果这很重要。


对于使用环境变量的方法,请参见https://dev59.com/VFfUa4cB1Zd3GeqPERKO。 - TooTone
12
"Corona SDK... 在2020年看起来很可怕。" - Simon Forsberg
5个回答

53

有一种方法可以推断出文件的“本地路径”(更具体地说,是用于加载文件的字符串)。

如果你正在 lib.foo.bar 中引用一个文件,你可能会像这样做:

require 'lib.foo.bar'

当你在所有函数外部时,可以将路径作为第一个(也是唯一的)...变量获取。换句话说:

-- lib/foo/bar.lua
local pathOfThisFile = ... -- pathOfThisFile is now 'lib.foo.bar'

现在,要获取“文件夹”,您需要删除文件名。 最简单的方法是使用match:

local folderOfThisFile = (...):match("(.-)[^%.]+$") -- returns 'lib.foo.'

现在你已经可以将这个字符串添加到其他文件名之前,并使用它来进行 require 操作:

require(folderOfThisFile .. 'baz')     -- require('lib.foo.baz')
require(folderOfThisFile .. 'bazinga') -- require('lib.foo.bazinga')

如果您移动bar.luafolderOfThisFile将自动更新。


4
这与加载文件无关,它只是反映了您选择如何构建 Lua 代码。例如,您可以在每次调用“require”时返回一个表格,并将其存储在本地变量中:local baz = require(folderOfThisFile .. 'baz'),然后使用 baz.some_value 来访问表格中的值。 - kikito
2
酷,我不知道函数外的 ... 是用来引用文件的字符串。 - Seth Carnegie
只需将以下代码添加到解决方案中,人们也可以使用“/”而不是“.”来要求模块,因此更通用的方法是:local folderOfThisFile = (...):match("(.-)[^%(.|/)]+$")" - houqp
@kikito,你是对的。但从Lua模块的角度来看,最好支持'.'和'/'两种方式,这样即使是“不可移植”的代码也可以使用它;) - houqp
@houqp 我不同意。在我看来,最好的方式是让模块强制执行标准并引发错误。这就像你期望参数中传递一个数字,但实际上却传递了一个字符串的情况一样。你应该抛出一个错误,说“这里需要一个数字”,而不是使用 tonumber 静默地将其转换为数字。 - kikito
显示剩余7条评论

27

你可以这样做

package.path = './mylib/?.lua;' .. package.path
或者
local oldreq = require
local require = function(s) return oldreq('mylib.' .. s) end
那么
-- do all the requires
require('mylib-utils')
require('mylib-helpers')
require('mylib-other-stuff')

-- and optionally restore the old require, if you did it the second way
require = oldreq

奇怪。我已经尝试更改package.path,并且认为自己做错了什么,因为它显示no field package.preload['mylib-utils']no file './mylib/mylib-utils.lua'。但是我正在使用Corona SDK内的Lua,也许它在加载文件方面有一些特殊性。 - RocketR
如果当前工作目录已更改(即您从另一个程序/路径运行脚本),则此方法将无法正常工作。 - klenium
如果修改后的 require() 中包含的任何内容自身调用 require() 并期望其正常工作,则此方法也无法正常工作。 - Caleb

2
我正在使用以下代码片段。它应该适用于通过require加载的文件和通过命令行调用的文件。然后,对于那些希望使用相对路径加载的文件,请使用requireRel代替require
local requireRel
if arg and arg[0] then
    package.path = arg[0]:match("(.-)[^\\/]+$") .. "?.lua;" .. package.path
    requireRel = require
elseif ... then
    local d = (...):match("(.-)[^%.]+$")
    function requireRel(module) return require(d .. module) end
end

0

试试这个:这是我的发现:

module1= require(".\\moduleName")
module2= dofile("..\\moduleName2.lua")
module3 =loadfile("..\\module3.lua")

从当前目录加载。在前缀为句点的双反斜杠后追加。

要指定上级目录,请使用两个句点的前缀,并对任何此类目录重复此模式。例如:

module4=require("..\\..\\module4")

0
在Conky的Lua环境下,我成功地将我的common.lua(在同一目录下)包含为require(".common")。请注意前导点.字符。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接