亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

Lua中模塊以及實現方法指南

2024-07-21 23:04:26
字體:
來源:轉載
供稿:網友

從使用的角度來看,一個模塊就是一個程序庫,可以通過Lua自身提供的require來加載。然后便得到一個全局變量,表示一個table。這個table就是像一個名字空間,其內容就是模塊導出的所有東西,例如函數和常量。簡單的說,Lua中的模塊就是一個table,table中可以包括任何東西。本文首先詳細介紹模塊相關的require函數,包括該函數的執行流程以及查找模塊的路徑,然后介紹了實現模塊的三種方法,并給出相應的優缺點。

 require函數

     該函數用來加載一個模塊,即按指定的路徑和傳入的參數,查找要加載的模塊。函數原型如下:

      require (modname)

      該函數的執行流程如下:

      I、查找表package.loaded,看modname是否已經加載過了。若是,則require函數直接返回package.loaded[modname],否則繼續執行,尋找模塊的加載器(loader)。

      II、為了尋找加載器,require使用了數組package.searchers(Lua 5.2引入的,在之前的版本叫做package.loaders,實質兩者只是名字不同而已),數組中每個元素是一個函數。

     第一個函數用來是搜索表package.preload,若存在,則返回相應的加載器。

     第二個函數是用來獲取Lua模塊的加載器,其搜索路徑存儲在package.path中,它是一個字符串,比如:

 

復制代碼 代碼如下:

/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua 

 

會用模塊名來替換每個”?”,然后根據替換的結果來檢測是否存在這樣的一個文件。這個工作是通過函數package.searchpath來做的。package.searchpath函數原型如下:
      package.searchpath (name, path [, sep [, rep]])

參數path是要查找的字符串,用分號隔開;name是要查找的文件;參數sep(默認值是”.”)可用于name中,在查找過程中用rep(默認值是系統目錄的分隔符)替換。比如path是

 

復制代碼 代碼如下:

"./?.lua;./?.lc;/usr/local/?/init.lua"

 

要查找foo.a,則會嘗試查找文件

 

復制代碼 代碼如下:

./foo/a.lua, ./foo/a.lc, 和/usr/local/foo/a/init.lua 

 

也就是說Lua支持具有層級性的模塊名。
      第三個函數是用來獲取C模塊的加載器,其搜索路徑存儲在package.cpath中,它也是一個字符串,比如:

 

復制代碼 代碼如下:

/usr/local/lib/lua/5.2/?.so;/usr/local/lib/lua/5.2/loadall.so;./?.so 

 

同樣會用模塊名來替換每個”?”,然后根據替換的結果來檢測是否存在這樣的一個文件。這個工作也是通過函數package.searchpath來做的。
     第四個函數是用all-in-one 加載器,使用這個功能,可以使得一個包里面包含多個C子模塊。除了第一個外,其他三個除了返回加載器外,還會返回找到的文件名作為額外的值。

      III、找到加載器后,require將用兩個參數調用這個加載器,一個是傳入的參數modname,另外一個是返回的額外值。如加載器返回一個不是nil的值,則把這個值賦值給package.loaded[modname]。如果加載返回返回一個nil并且加載器執行完后package.loaded[modname]還為空,則把package.loaded[modname]賦值為true。不管那種情況,require都會返回package.loaded[modname]。如果在這個過程有任務錯誤,require函數就產生一個錯誤給調用者。

     最后關于require函數,值得注意的幾點是:

     I、如果require找到的是一個lua文件,則通過loadfile來加載代碼,如果找到的是一個C程序庫,就通過loadlib來加載。注意,loadfile和loadlib都實質上加載代碼,并沒有運行他們。為了運行他們,require會用模塊名作為參數來調用這些代碼。

     II、若要強制使require對同一庫加載兩次,可以簡單刪除package.loaded中的模塊條目,即賦值相應的條目為nil。

     III、通過上面的加載過程分析知道,要加載自己的lua文件或C庫,可以通過修改package.path或package.cpath的值,把要搜索的路徑加載進去。

      IV、也可以定義自己的加載函數(除了已有的loadlib和loadfile等),比如加載ZIP文件,甚至從web上下載一個文件。

編寫模塊的方法

     方法一:對于Lua5.0和5.1來說,編寫模塊最簡單的方法是使用Lua自身提供的module函數(注意在Lua 5.2中被刪除了),比如要編寫一個模塊foo,模塊文件foo_file.lua如下:

 

復制代碼 代碼如下:

module("foo", package.seeall) 
function test() 
end 

 

則在其他文件要使用這個模塊,方式如下:

 

復制代碼 代碼如下:

require(“foo_file.lua”) 
foo.test() 

 

并且執行require后,則會把模塊foo就是全局環境的一個變量了,在其他地方也可以使用。module函數原型如下:

 

復制代碼 代碼如下:

module (name [, ···]) 

 

module在創建模塊table之前,會先檢查package.loaded是否已包括了這個模塊,或者是否已存在與模塊同名的變量。如果由此找到了這個table,它就會復用這個table做為模塊。也就是說,可以用module來打開一個已創建的模塊。

對于module函數來說,有以下問題,比如在模塊文件module0_test中有:

 

復制代碼 代碼如下:

module("mymodule", package.seeall)                                                                      
function foo() 
    print("Hello World!") 
end 

 

在另外一個文件可以這樣使用這個模塊:

 

復制代碼 代碼如下:

require "module0_test" 
mymodule.foo()             --Hello World! 
mymodule.print("example")  --example 

 

對于第二個調用不是報錯的,并且是非常奇怪的,這時因為module機制是在模塊中找不的成員,則去_G全局變量找,實現方式類似如下:

do   local globaltbl = _G   local newenv = setmetatable({}, {     __index = function (t, k)       local v = t[k]       if v == nil then return globaltbl[k] end       return v     end,     __newindex = M,   })   if setfenv then     setfenv(1, newenv) -- for 5.1   else     _ENV = newenv -- for 5.2   end end 

在模塊找不到的成員,則到_G中去查找,并且這樣訪問也是非常低效的,因為要通過元表來訪問成員。

 方法二:該方法的基本思想是讓模塊的主程序有一個獨占的環境,這樣所有函數或變量都共享這個table,并且所有的全局變量都記錄在這個table中,當然局部變量是不會的。代碼片段如下:

local modename = ... local M = {} _G[modename] = M package.loaded[modname] = M if setfenv then   setfenv(1, newenv) -- for 5.1 else   _ENV = newenv -- for 5.2 end 

如果這樣實現,在模塊訪問_G中的變量時,需要加上前綴,比如_G.print。為了解決這個問題,有幾種方法,各有優缺點:

 I、設置M的元表,即setmetable(M, {__index = _G})這樣做后,訪問全局變量,都要通過元表,開銷比較大。

 II、設置local _G = _G,這樣做后,訪問全局變量仍然要加上前綴,但速度更快。

 III、把模塊需要的全局變量都設置為局部變量,比如local io = io。這樣做會比較繁瑣,但是速度最快。

方法三:同樣是使用環境的概念。比如模塊文件如下:

 

復制代碼 代碼如下:

function foo()                                                                                          
    print("Hello World!")                                                                               
end 

 

為了使用它,方法如下:

local function Import(filename)                                       f = loadfile(filename)                                          local M = {}                                               setmetatable(M, {__index = _G})                                     setfenv(f,M)()   return M end  local FOO = Import("module2_test.lua")  FOO.foo() --output “Hello World!” 

用這種方法,只需調用Import方法,其返回值就是模塊,該方法把模塊相關訪問工作,放在使用的模塊的地方了。

以上所述就是本文的全部內容了,希望能夠對大家學習lua有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
一区二区三区www| 中文字幕欧美日韩精品| 久久精视频免费在线久久完整在线看| 亚洲国产精品热久久| 国模精品视频一区二区| 欧美高清不卡在线| 亚洲免费伊人电影在线观看av| 日本精品久久久久影院| 精品中文视频在线| 欧美性一区二区三区| 国产精品日日摸夜夜添夜夜av| 97国产真实伦对白精彩视频8| 亚洲国产精品人人爽夜夜爽| 久久精品一区中文字幕| 久久久精品视频成人| 国产情人节一区| 另类图片亚洲另类| 精品视频在线观看日韩| 国产精品日韩在线播放| 亚洲网站在线观看| 国产一级揄自揄精品视频| 狠狠色香婷婷久久亚洲精品| 九九综合九九综合| 欧美激情2020午夜免费观看| 日韩欧美在线播放| 一区二区三区动漫| 久久91亚洲人成电影网站| 狠狠躁夜夜躁人人爽超碰91| 欧美精品一本久久男人的天堂| 日韩三级影视基地| 国产日韩一区在线| 国产精品日韩在线观看| 久久亚洲精品一区二区| 国产+成+人+亚洲欧洲| 久久久999国产| 久久久久久久久91| 伊人伊成久久人综合网小说| 欧美日韩免费观看中文| 疯狂做受xxxx高潮欧美日本| 97视频在线播放| 欧美精品日韩三级| 精品国偷自产在线视频| 久久精品小视频| 韩国视频理论视频久久| 岛国视频午夜一区免费在线观看| 色偷偷av一区二区三区乱| 亚洲国产精品va在线观看黑人| 亚洲欧美在线一区| 国产精品电影观看| 日韩精品高清在线观看| 亚洲国产欧美日韩精品| 欧美亚洲国产日韩2020| xvideos亚洲人网站| 欧美日韩一区二区三区| 久久天天躁狠狠躁夜夜躁| 中文字幕亚洲一区二区三区五十路| 亚洲国产私拍精品国模在线观看| www.欧美视频| 欧美高清在线视频观看不卡| 国产成+人+综合+亚洲欧美丁香花| 国产+人+亚洲| 亚洲人午夜精品免费| 一区二区三区天堂av| 日韩av在线网站| 成人激情视频免费在线| 欧美性猛交xxxx久久久| 欧美人成在线视频| 亚洲欧美国产另类| 亚洲国产天堂久久综合| 少妇高潮久久久久久潘金莲| 日韩国产欧美精品在线| 91成人在线播放| 色爱av美腿丝袜综合粉嫩av| 国产精品一区二区在线| 国产成人精彩在线视频九色| 亚洲国产天堂久久综合| 久久6免费高清热精品| 亚洲tv在线观看| 国产精品r级在线| 一区二区三区四区在线观看视频| 欧美成人免费全部观看天天性色| 国产亚洲精品美女久久久久| 国产中文欧美精品| 成人乱人伦精品视频在线观看| 亚洲欧美日韩国产成人| 亚洲国产精品热久久| 国产精品久久久久久久久免费| 日本91av在线播放| 国产精品黄视频| 美女撒尿一区二区三区| 色吧影院999| 免费91麻豆精品国产自产在线观看| 中文字幕日韩电影| 国产精品视频99| 日韩免费在线看| 欧美一二三视频| 亚洲毛片一区二区| 亚洲精品乱码久久久久久按摩观| 亚洲美女视频网| 亚洲美女视频网站| 亚洲乱码一区av黑人高潮| 欧美性猛交99久久久久99按摩| 青青久久aⅴ北条麻妃| 国产日韩av在线播放| 91亚洲精品久久久久久久久久久久| 日韩综合视频在线观看| 亚洲а∨天堂久久精品喷水| 日本道色综合久久影院| 成人免费高清完整版在线观看| 国产91精品久久久| 欧美成人免费va影院高清| 国产精品美女久久久免费| 亚洲电影免费观看高清完整版在线| 97在线视频免费看| 日韩精品免费一线在线观看| 日韩一区二区久久久| 欧美性xxxx极品高清hd直播| 日韩经典一区二区三区| 亚洲国产毛片完整版| 国产精品极品美女在线观看免费| 国产综合香蕉五月婷在线| 九九精品在线观看| 国产精品视频白浆免费视频| 欧美成人激情视频| 久久免费精品日本久久中文字幕| 亚洲xxxx在线| 不卡中文字幕av| 日韩av网站大全| 欧美成人三级视频网站| 精品视频久久久久久| 亚洲乱码av中文一区二区| 国模私拍一区二区三区| 性夜试看影院91社区| 国产丝袜一区视频在线观看| 欧美成人黑人xx视频免费观看| 永久免费看mv网站入口亚洲| 欧美国产日韩视频| 91精品国产高清久久久久久久久| 国产欧美亚洲精品| 亚洲一区二区在线| 亚洲伊人一本大道中文字幕| 久久久久久久久久久成人| 亚洲最大的网站| 亚洲色图国产精品| 亚洲精品福利在线观看| 裸体女人亚洲精品一区| 国产精品久久久久99| 国产亚洲a∨片在线观看| 欧美视频在线观看免费网址| 欧美日韩高清在线观看| 97超碰色婷婷| 亚洲人成电影网| 国产一区二区三区在线观看视频| 日韩精品一区二区三区第95| 久久久精品视频在线观看| 欲色天天网综合久久| 欧美色播在线播放| 亚洲小视频在线观看| 最新亚洲国产精品| 亚洲国产91精品在线观看| 日韩三级成人av网| 国产精品私拍pans大尺度在线| 久久久www成人免费精品| 国产99视频在线观看|