lua require與module

來源:互聯網
上載者:User

標籤:lua require module

一、模組機制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)

lua require與module

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.