1. 程式人生 > >Lua中的模組與module函式

Lua中的模組與module函式

這篇文章主要介紹了Lua中的模組(module)和包(package)詳解,本文講解了require函式、寫一個模組、package.loadedmodule函式等內容.

    從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

中。當Lua啟動後,便以環境變數LUA_PATH的值來初始化這個變數。如果沒有找到該環境變數,則使用一個編譯時定義的預設路徑來初始化。如果require無法找到與模組名相符的Lua檔案,就會找C程式庫。C程式庫的搜尋模式存放在變數package.cpath中。而這個變數則是通過環境變數LUA_CPATH來初始化的。

 2. 編寫模組的基本方法:

    新建一個檔案,命名為game.lua,程式碼如下:

local M = {};
local modelName = ...;
_G[modelName] = M;
function M.play()
    print("那麼,開始吧");
end
function M.quit()
    print("你走吧,我保證你不會出事的,呵,呵呵");
end
return M;
    載入game.lua,程式碼如下:
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)