lua 之 require

注: 本篇文章从个人博客园移植而来

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

你可能感兴趣的:(Lua,lua)