Lua中的模組與module函式
這篇文章主要介紹了Lua中的模組(module)和包(package)詳解,本文講解了require函式、寫一個模組、package.loaded、module函式等內容.
從Lua5.1版本開始,就對模組和包添加了新的支援,可是使用require和module來定義和使用模組和包。require用於使用模組,module用於建立模組。簡單的說,一個模組就是一個程式庫,可以通過require來載入。然後便得到了一個全域性變數,表示一個table。這個table就像是一個名稱空間,其內容就是模組中匯出的所有東西,比如函式和常量,一個符合規範的模組還應使require返回這個table。現在就來具體的總結一下require和module這兩個函式。如:
require "mod"
mod.foo()
local m2 = require "mod2"
local f = mod2.foo
f()
1. require函式:
require函式的呼叫形式為require "模組名"。該呼叫會返回一個由模組函式組成的table,並且還會定義一個包含該table的全域性變數。在使用Lua中的標準庫時可以不用顯示的呼叫require,因為Lua已經預先載入了他們。
require函式在搜素載入模組時,有一套自定義的模式,如:
?;?.lua;c:/windows/?;/usr/local/lua/?/?.lua
在上面的模式中,只有問號(?)和分號(;)是模式字元,分別表示require函式的引數(模組名)和模式間的分隔符。如:呼叫require "sql",將會開啟以下的檔案:
sql
sql.lua
c:/windows/sql
/usr/local/lua/sql/sql.lua
Lua將require搜尋的模式字串放在變數package.path
2. 編寫模組的基本方法:
新建一個檔案,命名為game.lua,程式碼如下:
載入game.lua,程式碼如下:local M = {}; local modelName = ...; _G[modelName] = M; function M.play() print("那麼,開始吧"); end function M.quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end return M;
game = require "test"
game.play()
執行:>lua -e "io.stdout:setvbuf 'no'" "HelloWorld.lua"
那麼,開始吧
>Exit code: 0
3. 使用環境:
仔細閱讀上例中的程式碼,我們可以發現一些細節上問題。比如模組內函式之間的呼叫仍然要保留模組名的限定符,如果是私有變數還需要加local關鍵字,同時不能加模組名限定符。如果需要將私有改為公有,或者反之,都需要一定的修改。那又該如何規避這些問題呢?我們可以通過Lua的函式“全域性環境”來有效的解決這些問題。
我們把game.lua這個模組裡的全域性環境設定為M,於是,我們直接定義函式的時候,不需要再帶M字首。
因為此時的全域性環境就是M,不帶字首去定義變數,就是全域性變數,這時的全域性變數是儲存在M裡。
所以,實際上,play和quit函式仍然是在M這個table裡。
local M = {};
local modelName = ...;
_G[modelName] = M;
package.loaded[modname] = M
setfenv(1, M);
function play()
print("那麼,開始吧");
end
function quit()
print("你走吧,我保證你不會出事的,呵,呵呵");
end
return M;
4. module函式:
在Lua 5.1中,我們可以用module(...)函式來代替以下程式碼,如:
local modname = ...
local M = {}
_G[modname] = M
package.loaded[modname] = M
--[[
和普通Lua程式塊一樣宣告外部函式。
--]]
setfenv(1,M)
即是:module(..., package.seeall);
function play()
print("那麼,開始吧")
end
function quit()
print("你走吧,我保證你不會出事的,呵,呵呵");
end
由於在預設情況下,module不提供外部訪問,必須在呼叫它之前,為需要訪問的外部函式或模組宣告適當的區域性變數。然後Lua提供了一種更為方便的實現方式,即在呼叫module函式時,多傳入一個package.seeall的引數,相當於 setmetatable(M, {__index = _G}) .如:
module(...,package.seeall)