溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

lua require與module

發(fā)布時(shí)間:2020-07-26 18:17:30 來(lái)源:網(wǎng)絡(luò) 閱讀:2546 作者:bosswanghai 欄目:開(kāi)發(fā)技術(shù)

一、模塊機(jī)制module

    1.什么是module

對(duì)于用戶來(lái)說(shuō),一個(gè)module相當(dāng)于一個(gè)so庫(kù)。模塊的主要目標(biāo)是實(shí)現(xiàn)代碼的共享。

    2.如何編寫(xiě)module

lua是通過(guò)table來(lái)實(shí)現(xiàn)模塊的,典型的寫(xiě)法如下。

local M = {}        ---- 通常是加local的,如果不加,則M默認(rèn)注冊(cè)到_G中,require后,即使不return也可以直接使用M。加了local是局部變量,需要顯示的return一下。

M.print = function(...)

    print(...)

end

return M


二、require機(jī)制

    1.require實(shí)現(xiàn)原理:

function require(name)

    if not packge.loaded[name] then        ---- 避免重復(fù)加載

        local loader = findloader(name)        ---- 如果是so,就以loadlib方式加載文件,如果是lua文件,就以loadfile方式加載文件。

        if loader == nil then

            error("unable to load module " .. name)

        end

        package.loaded[name] = true         ---- 將模塊標(biāo)記為以加載,我們有時(shí)候會(huì)看到require返回true的現(xiàn)象,是由于被調(diào)用的模塊,沒(méi)有顯示的執(zhí)行package.loaded[modname] = M或者給出return M這樣的返回值。

        local res = loader(name)        ---- require會(huì)以name作為入?yún)?lái)執(zhí)行該文件,如果有返回結(jié)果,就將返回結(jié)果保存在package.loaded[name]中,如果沒(méi)有返回結(jié)果,就直接返回package.loaded[name]。如果我們?cè)诒徽{(diào)用的文件中直接寫(xiě)明return 1。則調(diào)用者的require的返回結(jié)果就是1。但是只要我們顯示的在require文件中寫(xiě)明了_G[modname] = M,我們?nèi)匀豢梢栽趓equire之后,直接使用M作為名字來(lái)調(diào)用,是由于將M加入到了_G中。

        if res ~= nil then

            package.loaded[name] = res

        end

    end

    return package.loaded[name]

end

        

    2.require實(shí)現(xiàn)解析:

    傳參: require會(huì)將模塊名作為參數(shù)傳遞給模塊

    返回值:如果一個(gè)模塊沒(méi)有返回值的話,require就會(huì)返回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()


執(zhí)行結(jié)果:

lua mob.lua

pa

------------------------------------------------------------

分析:

pa.lua中的modname接收的是require傳遞過(guò)來(lái)的參數(shù),將其加入到全局環(huán)境變量_G中,相當(dāng)于動(dòng)態(tài)創(chuàng)建了一個(gè)modname的表(注意:表名的賦值實(shí)際上是引用,相當(dāng)于C語(yǔ)言中的指針,即使是傳參也會(huì)有相同的效果)。我們經(jīng)常local m = require "mdname",實(shí)際上是將生成的表進(jìn)行了重命名,但是本質(zhì)上還是mdname這個(gè)表。

pa.lua中的return M我們沒(méi)有顯示聲明,由package.loaded[modulename]來(lái)代替,通過(guò)require實(shí)現(xiàn)機(jī)制可以看到,這時(shí)候返回值應(yīng)該是true。


三、環(huán)境

lua用_G一張表保存了全局?jǐn)?shù)據(jù)(變量,函數(shù)和表等)。

如上分析,我們定義一個(gè)module,如果不加local,則它是一個(gè)注冊(cè)在全局下的表。我們通過(guò)加local避免了它在污染全局表空間,只在本文件生效。如果我們沒(méi)有將其注冊(cè)到_G下,在其他文件是無(wú)法直接通過(guò)他的原始名字來(lái)訪問(wèn)的。不便利的地方,每個(gè)函數(shù)前面都要帶M,M的下的函數(shù)相互訪問(wèn)也要帶M頭。

解決方法:通過(guò)setfenv

local modname = ...

local M = {}


_G[modname] = M

package.loaded[modname] = M

setfenv(1, M)

后續(xù)的函數(shù)直接定義名字,因?yàn)樗麄兊沫h(huán)境空間已經(jīng)由_G改為了M。

如果要使用全局函數(shù),則可以本地額外增加一條local _G = _G或者setmetatable(M, {__index = G})。

更好的方法是在setfenv之前將需要的函數(shù)都保存起來(lái),local sqrt = math.sqrt


四、module函數(shù)

local M = {}

_G[modname] = M

package.loaded[modname] = M

<set for external access: eg setmetatable(M, {__index = _G})>

setfenv(1, M)

等同于module(modname)。

默認(rèn)情況下,module不提供外部訪問(wèn),如果要訪問(wèn)外部變量,兩種方法:

1.在聲明module之前,local 變量 = 外部變量

2.使用module(modname, package.seeall), 等價(jià)于setmetatable(M, __index = _G)

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI