注: 本篇文章从个人博客园移植而来
require
require作用类似于C/C++中的#include,特性:
-
根据搜索目录加载指定模块
-
判定模块是否已加载,避免重复加载
加载的模块数据存储在package.loaded
表中。
其存储方式以模块名为key,以返回值(若无返回值,默认true)为value进行存储的
-- 导入任意lua文件
require("Demo")
require("Demo") -- 重复文件不会加载的
require ("Desktop.Demo2") -- 会将“.”替换为“/”
require ("Desktop/File/Demo1")
-- 遍历加载的lua文件表
for key, value in pairs(package.loaded) do
print(key,value)
end
--[[
输出:
string table: 002DDE40
debug table: 002DDF08
package table: 002DDAF8
_G table: 008C1C88
io table: 002DDC88
os table: 002DDDC8
table table: 002DDB98
math table: 002DDEB8
coroutine table: 002DDA58
Demo true -- 新加,导入的重复文件不会在加载
Desktop.Demo2 true -- 新加
Desktop/File/Demo3 true -- 新加
]]
关于require的实现逻辑看下:
-- 参考:Lua程序设计(第2版)
function require(name)
-- 判定模块是否已加载,若已加载将直接返回,避免重复加载
if not package.loaded[name] then
-- 搜索模块
local loader = findloader(name)
if loader == nil then
-- 模块不存在,报错
error("unable to load module " .. name)
end
-- 将模块先默认设置为true
package.loaded[name] = true
-- 初始化模块,若模块存在返回值,将true替换为返回值数据
local res = loader(name)
if res ~= nil then
package.loaded[name] = res
end
end
-- 返回模块数据
return package.loaded[name]
end
require的搜索
如果试图添加加载一个不存在的文件:
-- 加载不存在的模块
require("ErrorModel")
--[[
错误堆栈信息:
lua: require.lua:21: module 'ErrorModel' not found:
no field package.preload['ErrorModel']
no file '.\ErrorModel.lua'
no file 'E:\Program Files (x86)\Lua\5.1\lua\ErrorModel.lua'
no file 'E:\Program Files (x86)\Lua\5.1\lua\ErrorModel\init.lua'
no file 'E:\Program Files (x86)\Lua\5.1\ErrorModel.lua'
no file 'E:\Program Files (x86)\Lua\5.1\ErrorModel\init.lua'
no file 'E:\Program Files (x86)\Lua\5.1\lua\ErrorModel.luac'
no file '.\ErrorModel.dll'
no file '.\ErrorModel51.dll'
no file 'E:\Program Files (x86)\Lua\5.1\ErrorModel.dll'
no file 'E:\Program Files (x86)\Lua\5.1\ErrorModel51.dll'
no file 'E:\Program Files (x86)\Lua\5.1\clibs\ErrorModel.dll'
no file 'E:\Program Files (x86)\Lua\5.1\clibs\ErrorModel51.dll'
no file 'E:\Program Files (x86)\Lua\5.1\loadall.dll'
no file 'E:\Program Files (x86)\Lua\5.1\clibs\loadall.dll'
stack traceback:
[C]: in function 'require'
require.lua:21: in main chunk
[C]: ?
]]
对比者错误的信息日志查看,可以简单的了解到搜索路径主要有:
- 搜索
.lua/.luac
的Lua文件相关 - 搜索
.lib
的C库文件相关
在cocos2d-x中, 关于搜索路径的配置相关,主要有:
- Lua主要通过
LUA_PATH
来实现配置路径相关 - C主要通过
LUA_CPATH
来实现配置路径相关
// luaconf.h
#define LUA_PATH "LUA_PATH"
#define LUA_CPATH "LUA_CPATH"
// 如果没有配置LUA_PATH,LUA_CPATH会走默认的路径
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;"
#define LUA_CPATH_DEFAULT \
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
初始化后,会将lua配置路径放置到package.path
中, C配置相关放置到package.cpath
中
print("package.path路径相关:")
print(package.path)
--[[
-- 为了便于查看,进行了分行
;
.\?.lua;
E:\Program Files (x86)\Lua\5.1\lua\?.lua;
E:\Program Files (x86)\Lua\5.1\lua\?\init.lua;
E:\Program Files (x86)\Lua\5.1\?.lua;
E:\Program Files (x86)\Lua\5.1\?\init.lua;
E:\Program Files (x86)\Lua\5.1\lua\?.luac
]]
print("package.cpath路径相关:")
print(package.cpath)
--[[
-- 为了便于查看,进行了分行
.\?.dll;
.\?51.dll;
E:\Program Files (x86)\Lua\5.1\?.dll;
E:\Program Files (x86)\Lua\5.1\?51.dll;
E:\Program Files (x86)\Lua\5.1\clibs\?.dll;
E:\Program Files (x86)\Lua\5.1\clibs\?51.dll;
E:\Program Files (x86)\Lua\5.1\loadall.dll;
E:\Program Files (x86)\Lua\5.1\clibs\loadall.dll
]]
关于?
就相当于模版路径
,程序在搜索模块的时候,会将模块名替换为?
。
主要通过package.searchpath
来实现搜索。实现代码类似于:
function search(modname, path)
-- 将“.”替换为“/”
modname = string.gsub(modname, "%.", "/")
local msg = {}
for c in string.gmatch(path, "[^;]+") do
-- 将“?”替换为模块名
local fname = string.gsub(c, "?", modname)
-- 检测文件是否存在
local f = io.open(fname)
if f then
f:close()
return fname
else
msg[#msg + 1] = string.format("\n\t no file '%s'", fname)
end
end
return nil, table.concat(msg) -- 没有找到
end
关于package.searchpath的搜索相关,主要有三个方面吧:
-
预加载搜索
,通过package.preload
来进行 -
Lua中搜索
,通过package.path获取搜索路径,成功后会调用loadFile
加载 -
C库中搜索
,通过package.cpath获取搜索路径,成功后,会调用loadlib
来加载
加载成功后,会添加到package.loaded
中。
End