lua require

環境: html

Lua5.1  LuaForWindowswindows

LuaForWindows的下載地址ide

http://files.luaforge.net/releases/luaforwindows/luaforwindowsui

 

正題:lua

require做用相似於C/C++中的#include,其特性爲:spa

1. 根據搜索目錄加載指定模塊.net

2. 斷定模塊是否已加載,避免重複加載debug

其實現原理:設計

  對於require加載的模塊數據是存儲在package.loaded表中,其存儲方式以模塊名爲key,以返回值(模塊若無返回值,默認爲true)爲value進行存儲的。好比運行以下程序:code

-- package.loaded的類型
print(type(package.loaded))      -- table
-- 沒有require模塊文件
for i, v in pairs(package.loaded) do
    print(i,v)
end

--[[
>>>輸出
string    table: 006EDE40
debug    table: 006EDF08
package    table: 006EDAF8
_G    table: 00501C88
io    table: 006EDC88
os    table: 006EDDC8
table    table: 006EDB98
math    table: 006EDEB8
]]

而後咱們任意加載一個Demo.lua,代碼以下:

-- requireDemo.lua
-- 內部實現代碼: 
local requireDemo = {}
return true
require("requireDemo")
for i, v in pairs(package.loaded) do
    print(i,v)
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
requireDemo    true                      -- 新加的,已經加入到表中了        
]]    

通過如上代碼對比,咱們能夠這樣理解,經過require加載某模塊的時候,首先經過package.loaded來斷定是否已加載。若是已加載,則返回該模塊數據,若是沒有加載,進行搜索加載,若是加載成功,返回該模塊數據,不然報錯。好比:

-- 加載不存在的模塊
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和C中的相關文件。咱們來詳細的說明下:

在程序中,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"
#else
/*
** Note to distribution maintainers: do NOT patch the following lines!
** Please read ../doc/install.html#distro and pass PREFIX=/usr instead.
*/
#ifndef LUA_MULTILIB
#define LUA_MULTILIB    "lib"
#endif
#ifndef LUA_LMULTILIB
#define LUA_LMULTILIB    "lib"
#endif
#define LUA_LROOT    "/usr/local"
#define LUA_LUADIR    "/lua/5.1/"
#define LUA_LJDIR    "/luajit-2.1.0-beta2/"

#ifdef LUA_ROOT
#define LUA_JROOT    LUA_ROOT
#define LUA_RLDIR    LUA_ROOT "/share" LUA_LUADIR
#define LUA_RCDIR    LUA_ROOT "/" LUA_MULTILIB LUA_LUADIR
#define LUA_RLPATH    ";" LUA_RLDIR "?.lua;" LUA_RLDIR "?/init.lua"
#define LUA_RCPATH    ";" LUA_RCDIR "?.so"
#else
#define LUA_JROOT    LUA_LROOT
#define LUA_RLPATH
#define LUA_RCPATH
#endif

#define LUA_JPATH    ";" LUA_JROOT "/share" LUA_LJDIR "?.lua"
#define LUA_LLDIR    LUA_LROOT "/share" LUA_LUADIR
#define LUA_LCDIR    LUA_LROOT "/" LUA_LMULTILIB LUA_LUADIR
#define LUA_LLPATH    ";" LUA_LLDIR "?.lua;" LUA_LLDIR "?/init.lua"
#define LUA_LCPATH1    ";" LUA_LCDIR "?.so"
#define LUA_LCPATH2    ";" LUA_LCDIR "loadall.so"

#define LUA_PATH_DEFAULT    "./?.lua" LUA_JPATH LUA_LLPATH LUA_RLPATH
#define LUA_CPATH_DEFAULT    "./?.so" LUA_LCPATH1 LUA_RCPATH LUA_LCPATH2
#endif

初始化後,會將相關的路徑分別放置到package.path,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中,其搜索的路徑實質上屬於模板路徑,在搜索模塊時,首先會把模塊名替換模塊路徑下的"?",再進行開始搜索。

從實質上來講,搜索的步驟依次分爲以下部分:

1. 預加載搜索,經過package.preload來進行

2. Lua中搜索,經過package.path獲取搜索路徑,成功後會調用loadFile加載

3. C庫中搜索,經過package.cpath獲取搜索路徑,成功後,會調用loadlib來加載

加載成功後,會存儲到表package.loaded中。

 

其它:可否從新加載模塊嗎?

答案能夠,咱們須要將已加載模塊的表置空,以下:

package.loaded["*"] = nil      -- 置空已加載的模塊數據
required("*")             -- 再次加載

 關於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 -- 將模塊標記爲已加載 package.loaded[name] = true -- 初始化模塊 local res = loader(name) if res ~= nil then package.loaded[name] = res end end -- 返回模塊數據 return package.loaded[name] end
相關文章
相關標籤/搜索