您好,登錄后才能下訂單哦!
一、模塊機制module
1.什么是module
對于用戶來說,一個module相當于一個so庫。模塊的主要目標是實現代碼的共享。
2.如何編寫module
lua是通過table來實現模塊的,典型的寫法如下。
local M = {} ---- 通常是加local的,如果不加,則M默認注冊到_G中,require后,即使不return也可以直接使用M。加了local是局部變量,需要顯示的return一下。
M.print = function(...)
print(...)
end
return M
二、require機制
1.require實現原理:
function require(name)
if not packge.loaded[name] then ---- 避免重復加載
local loader = findloader(name) ---- 如果是so,就以loadlib方式加載文件,如果是lua文件,就以loadfile方式加載文件。
if loader == nil then
error("unable to load module " .. name)
end
package.loaded[name] = true ---- 將模塊標記為以加載,我們有時候會看到require返回true的現象,是由于被調用的模塊,沒有顯示的執行package.loaded[modname] = M或者給出return M這樣的返回值。
local res = loader(name) ---- require會以name作為入參來執行該文件,如果有返回結果,就將返回結果保存在package.loaded[name]中,如果沒有返回結果,就直接返回package.loaded[name]。如果我們在被調用的文件中直接寫明return 1。則調用者的require的返回結果就是1。但是只要我們顯示的在require文件中寫明了_G[modname] = M,我們仍然可以在require之后,直接使用M作為名字來調用,是由于將M加入到了_G中。
if res ~= nil then
package.loaded[name] = res
end
end
return package.loaded[name]
end
2.require實現解析:
傳參: require會將模塊名作為參數傳遞給模塊
返回值:如果一個模塊沒有返回值的話,require就會返回package.loaded[modulename]作為返回值。
------------------------example---------------------
舉例:
pa.lua:
local modname = ...
local M = {}
_G[modname] = M
package.loaded[modname] = M
function M.print_mob()
print(modname)
end
mob.lua:
require "pa"
pa.print_mob()
執行結果:
lua mob.lua
pa
------------------------------------------------------------
分析:
pa.lua中的modname接收的是require傳遞過來的參數,將其加入到全局環境變量_G中,相當于動態創建了一個modname的表(注意:表名的賦值實際上是引用,相當于C語言中的指針,即使是傳參也會有相同的效果)。我們經常local m = require "mdname",實際上是將生成的表進行了重命名,但是本質上還是mdname這個表。
pa.lua中的return M我們沒有顯示聲明,由package.loaded[modulename]來代替,通過require實現機制可以看到,這時候返回值應該是true。
三、環境
lua用_G一張表保存了全局數據(變量,函數和表等)。
如上分析,我們定義一個module,如果不加local,則它是一個注冊在全局下的表。我們通過加local避免了它在污染全局表空間,只在本文件生效。如果我們沒有將其注冊到_G下,在其他文件是無法直接通過他的原始名字來訪問的。不便利的地方,每個函數前面都要帶M,M的下的函數相互訪問也要帶M頭。
解決方法:通過setfenv
local modname = ...
local M = {}
_G[modname] = M
package.loaded[modname] = M
setfenv(1, M)
后續的函數直接定義名字,因為他們的環境空間已經由_G改為了M。
如果要使用全局函數,則可以本地額外增加一條local _G = _G或者setmetatable(M, {__index = G})。
更好的方法是在setfenv之前將需要的函數都保存起來,local sqrt = math.sqrt
四、module函數
local M = {}
_G[modname] = M
package.loaded[modname] = M
<set for external access: eg setmetatable(M, {__index = _G})>
setfenv(1, M)
等同于module(modname)。
默認情況下,module不提供外部訪問,如果要訪問外部變量,兩種方法:
1.在聲明module之前,local 變量 = 外部變量
2.使用module(modname, package.seeall), 等價于setmetatable(M, __index = _G)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。