在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
环境: Lua5.1 工具:LuaForWindows(http://files.luaforge.net/releases/luaforwindows/luaforwindows)
require作用类似于C/C++中的#include,特性: 1. 根据搜索目录加载指定模块 2. 判定模块是否已加载,避免重复加载 require加载的模块数据存储在 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 -- 新加 ]] 如果我们试图加载一个不存在的lua文件: -- 加载不存在的模块 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]: ? ]] 我们看下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实现原理。因此重载模块数据的话,我们可以这样: package.loaded["*"] = nil -- 置空已加载的模块数据 require("*") -- 再次加载
对比着错误的堆栈信息我们可以简单的了解到findloader的搜索路径主要有: 1. Lua文件路径相关 2. C库文件路径相关 我们来说明下findloader搜索路径相关。lua通过LUA_PATH进行初始化,C通过LUA_CPATH进行初始化: // luaconf.h // Environment variable names for path overrides and initialization code #define LUA_PATH "LUA_PATH" #define LUA_CPATH "LUA_CPATH" 若LUA_PATH,LUA_CPATH没有相关的变量,会通过LUA_PATH_DEFAULT,LUA_CPATH_DEFAULT来进行默认初始化,代码如下: // luaconf.h /* ** 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 ]] 如上其模块名的显示"?",在lua中,其搜索的路径实质上属于模板路径。即在搜索模块时,首先会把模块名替换模块路径下的"?",再进行通过package.searchpath搜索。比如: ?; ?.lua; c:\windows\?; /usr/local/lua/lua/?/?.lua
关于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.searchers会列出require使用的所有搜索器,主要有三部分: 1. 预加载搜索,通过package.preload来进行 2. Lua中搜索,通过package.path获取搜索路径,成功后会调用loadFile加载 3. C库中搜索,通过package.cpath获取搜索路径,成功后,会调用loadlib来加载
加载成功后,会添加到package.loaded中。
|
请发表评论