主頁 > 知識(shí)庫 > 解析Lua中的全局環(huán)境、包、模塊組織結(jié)構(gòu)

解析Lua中的全局環(huán)境、包、模塊組織結(jié)構(gòu)

熱門標(biāo)簽:Linux服務(wù)器 呼叫中心市場需求 服務(wù)外包 鐵路電話系統(tǒng) 地方門戶網(wǎng)站 AI電銷 百度競價(jià)排名 網(wǎng)站排名優(yōu)化

模塊就是一個(gè)程序庫,而包是一系列模塊。Lua中可以通過require來加載模塊,然后得到一個(gè)全局變量表示一個(gè)table。Lua將其所有的全局變量保存在一個(gè)被稱為“環(huán)境”的常規(guī)table中。本文首先介紹環(huán)境的一些實(shí)用技術(shù),然后介紹如何引用模塊及編寫模塊的基本方法。

1. 環(huán)境
Lua將環(huán)境table保存在一個(gè)全局變量_G中,可以對(duì)其訪問和設(shè)置。有時(shí)我們想操作一個(gè)全局變量,而它的名稱卻存儲(chǔ)在另一個(gè)變量中,或者需要通過運(yùn)行時(shí)的計(jì)算才能得到,可以通過value = _G[varname]來獲得動(dòng)態(tài)名字的全局變量。

關(guān)于“環(huán)境”的一大問題是它是全局的,任何對(duì)它的修改都會(huì)影響程序的所有部分。Lua 5允許每個(gè)函數(shù)擁有一個(gè)子集的環(huán)境來查找全局變量,可以通過setfenv來改變一個(gè)函數(shù)的環(huán)境,第一個(gè)參數(shù)若是1則表示當(dāng)前函數(shù),2則表示調(diào)用當(dāng)前函數(shù)的函數(shù)(依次類推),第二個(gè)參數(shù)是一個(gè)新的環(huán)境table。

a = 1
setfenv(1, {})
print(a) -- 會(huì)報(bào)錯(cuò),print是一個(gè)nil。這是因?yàn)橐坏└淖儹h(huán)境,所有的全局訪問都會(huì)使用新的table

為了避免上述問題,可以使用setfenv(1, {_G = _G})將原來的環(huán)境保存起來,然后用_G.print來引用。另一種組裝新環(huán)境的方法是使用繼承,下面的代碼新環(huán)境從源環(huán)境中繼承了print和a,任何賦值都發(fā)生在新的table中。

a = 1
local newgt = {}
setmetatable(newgt, {__index = _G})
setfenv(1, newgt)
print(a)

2. 模塊與包
2.1 調(diào)用模塊

要調(diào)用模塊mod中的foo方法,可以用require函數(shù)來加載,如:

require "mod"
mod.foo()
-- 或者
local m = require "mod"
m.foo()

require函數(shù)的行為: (關(guān)于require使用的路徑查找策略不贅述)
在package.loaded這個(gè)table中檢查模塊是否已加載
=> 已加載,就返回相應(yīng)的值(可見一個(gè)模塊只會(huì)加載一次)
=> 未加載,就試著在package.preload中查詢傳入的模塊名
===> 找到一個(gè)函數(shù),就以該函數(shù)作為模塊的加載器
===> 找不到,則嘗試從Lua文件或C程序庫中加載模塊
=====> 找到Lua文件,通過loadfile來加載文件
=====> 找到C程序庫,通過loadlib來加載文件

2.2 使用環(huán)境

下面的代碼說明了如何用環(huán)境來創(chuàng)建一個(gè)復(fù)數(shù)(complex)模塊:

-- 模塊設(shè)置
local modname = "complex"
local M = {}
_G[modname] = M
package.loaded[modname] = M

-- 聲明模塊從外界所需的所有東西
local _G = _G -- 保留舊環(huán)境的引用,使用時(shí)需要像_G.print這樣用
local io = io

-- 運(yùn)行這句之后環(huán)境就變了
setfenv(1, M)

function new(r, i) return {r=r, i=i} end

function add(c1, c2)
  return new(c1.r + c2.r, c1.i + c2.i)
end

這樣聲明函數(shù)add時(shí),就成為了complex.add,調(diào)用同一模塊的其他函數(shù)也不需要加前綴。

2.3 module函數(shù)

Lua 5.1提供了一個(gè)新函數(shù)module,囊括了上面一系列定義環(huán)境的功能。在開始編寫一個(gè)模塊時(shí),可以直接用module("modname", package.seeall)來取代前面的設(shè)置代碼。在一個(gè)模塊文件開頭有這句調(diào)用后,后續(xù)所有代碼都不需要限定模塊名和外部名字,同樣也不需要返回模塊table了。

2.4 子模塊與包

Lua支持具有層級(jí)的模塊名,用一個(gè)點(diǎn)來分隔名稱中的層級(jí)。例如一個(gè)模塊名為mod.sub,就是mod的一個(gè)子模塊。一個(gè)包(package)就是一個(gè)完整的模塊樹,它是Lua中發(fā)型的單位。注意,當(dāng)搜索一個(gè)子模塊文件時(shí),require會(huì)把點(diǎn)號(hào)當(dāng)做目錄分隔符來搜索,也就是說調(diào)用require "a.b"會(huì)嘗試打開./a/b.lua,/usr/local/lua/a/b.lua,/usr/local/lua/a/b/init.lua。通過這種加載策略,可以將包的所有模塊組織到一個(gè)目錄中。

2.5 以自定義方式加載 lua 模塊
從 Lua 5.1 以后,Lua 有了標(biāo)準(zhǔn)的模塊管理庫。所以所有的模塊加載都是通過 require 來完成。 require 的設(shè)計(jì)是頗具擴(kuò)展性的,它會(huì)從若干個(gè)定義好的 loader 中逐個(gè)嘗試加載新的模塊。系統(tǒng)庫中提供了四個(gè) loader ,分別實(shí)現(xiàn)已加載模塊,Lua 模塊,和 C 擴(kuò)展模塊(用了兩個(gè) loader 來實(shí)現(xiàn) C 擴(kuò)展模塊的加載)。這些 loader 以 CFunction 的形式放在 require 的環(huán)境中的一個(gè) table 里。

如果我們想改變 lua 模塊的加載形式,只需要替換或增加一個(gè)新的 loader 就可以了。

要做的只需要模仿 loadlib.c 中的 loader_Lua 函數(shù)做一個(gè)自己的實(shí)現(xiàn),比如在我們的項(xiàng)目中,就允許從自定義格式數(shù)據(jù)包中,加載一個(gè)被加密過的 Lua 代碼文件。然后寫幾行 C 代碼,獲得 require 的環(huán)境(使用 lua_getfenv ),然后取出其中 "loaders" 這個(gè) table ,把新的自定義 loader 插入到 index 2 的地方。

具體的代碼就不詳述了,仔細(xì)閱讀一下 ll_require 的實(shí)現(xiàn)(在 loadlib.c 中)就很容易明白。我們的整個(gè)工作從分析到實(shí)現(xiàn)沒有超過兩個(gè)小時(shí),這真是得益于 Lua 良好的設(shè)計(jì)啊 :D 甚至如果你想從一個(gè)網(wǎng)絡(luò)連接的數(shù)據(jù)流中加載 Lua 模塊,或是通過 http/ftp 協(xié)議下載,也是行的通的吧。

您可能感興趣的文章:
  • 解決nginx+lua搭建文件上傳下載服務(wù)問題
  • Lua在windows下的安裝及環(huán)境配置
  • 安裝Nginx+Lua開發(fā)環(huán)境
  • Mac平臺(tái)中編譯安裝Lua運(yùn)行環(huán)境及Hello Lua實(shí)例
  • Lua在各個(gè)操作系統(tǒng)中的開發(fā)環(huán)境配置教程
  • Lua的函數(shù)環(huán)境、包實(shí)例講解
  • linux系統(tǒng)安裝Nginx Lua環(huán)境
  • 如何使用Vim搭建Lua開發(fā)環(huán)境詳解

標(biāo)簽:黃山 仙桃 崇左 衡水 蘭州 銅川 湘潭 湖南

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《解析Lua中的全局環(huán)境、包、模塊組織結(jié)構(gòu)》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266