Lua中的環境概念

2021-07-24 16:42:43 字數 2253 閱讀 4264

2014-07-29

分類:lua

閱讀(1834) 前言

lua將其所有的全域性變數儲存在乙個常規的table中,這個table稱為「環境」。這種組織結構的優點在於,其一,不需要再為全域性變數創造一種新的資料結構,因此簡化了lua的內部實現;另乙個優點是,可以像其他table一樣操作這個table。為了便於實施這種操作,lua將環境table自身儲存在乙個全域性變數_g中。例如,我們可以使用以下**列印當前環境中所有全域性變數的名稱。

for

n in

pairs(_g

)doprint(n

)end

在你的電腦上執行一下以上**,看看結果。

全域性變數宣告

在lua中,全域性變數不需要宣告就可以直接使用,但是這樣違反了程式設計的大忌,隨便使用全域性變數,將導致程式的效能,當出現bug時,也很難去發現,同時也汙染了程式中的命名。考慮到全域性變數也是存放在乙個table中,我們則可以通過元表來改變其它**訪問全域性變數時的行為,看到了麼?又是元表。**如下:

setmetatable(_g

,)print(a

)--這裡a

就是乙個全域性變數

而有的時候,我們的確需要定義乙個全域性變數,那怎麼辦?還記得我在《lua中的元表與元方法》這篇文章中寫的嗎?使用rawset就可以完成,它是不同過元表的,直接設定table的值;同時,為了測試乙個變數是否存在,就不能簡單的將它與nil比較。因為如果它為nil,訪問就會丟擲乙個錯誤,同樣,我們可以使用rawget來繞過元方法。

非全域性的變數

由於「環境」這個概念是全域性的,任何對他的修改都會影響程式的所有部分。例如:若安裝乙個元表用於控制全域性變數的訪問,那麼整個程式都必須遵循這個規範。但使用某個庫時,沒有先宣告就使用了全域性變數,那麼這個程式就無法執行了。

可以通過函式setfenv來改變乙個函式的環境。該函式的引數是乙個函式和乙個新的環境table。第乙個引數除了可以指定為函式本身,還可以指定為乙個數字,以表示當前函式呼叫棧中的層數。數字1表示當前函式,數字2表示呼叫當前函式的函式,以此類推。首先來一小段**:

a =1

--這裡建立了乙個全域性變數

--將當前環境變數改為乙個新的空

table

setfenv(1

,{})

print(a

)

執行**會彈出這樣的錯誤:attempt to call global 『print』 (a nil value)

print是存放在_g中的,由於我們將當前的環境變數重置為了乙個空的table,導致找不到print了,所以就出現了錯誤。為了防止這樣的錯誤的放生,在我們改變當前的環境變數之前,我們需要儲存當前的環境變數。看下面的**:

a =1

--這裡建立了乙個全域性變數

--將當前環境變數改為乙個新的空

table

setfenv(1

,)g.

print(a

)--輸出nilg.

print(g

.a)--

輸出1

這個時候訪問g就會得到原來的環境,這個環境中包含了字段print。我們可以使用名字_g來代替g,如下述**:

a =1

--這裡建立了乙個全域性變數

--將當前環境變數改為乙個新的空

table

setfenv(1

,)_g.

print(a

)--輸出nil_g.

print(_g

.a)--

輸出1

不要忘了我們之前總結的__index元方法,我們可以設定新的環境變數的__index為_g,這樣,當在新的環境中找不到對應的變數時,就會去_g中找,這樣,就相當於新的環境變數繼承了全域性的環境變數_g,看以下**:

a =1

--這裡建立了乙個全域性變數

local

newenv ={}

setmetatable

(newenv,)

--將當前環境變數改為乙個新的空

table

setfenv(1

,newenv

)print(a

)

在lua中,函式會繼承建立其的環境,所以乙個程式塊若改變了它自己的環境,那麼後續由它建立的函式都將共享這個新環境。這項機制對於建立命名空間是很有用的。之後的總結中還會繼續講解的。

2023年7月29日 於深圳。

詳解Lua中的元表概念

有跡象表明,在處理metatables其中包括使用了兩種重要的方法,讓我們先來看看如何設定乙個表作為另乙個元表。它如下所示。複製 如下 mytable mymetatable setmetatable mytable,mymetatable 上面的 可以在乙個單一的行被表示為如下所示。複製 如下 m...

詳解Lua中的陣列概念知識

陣列是有序的物件的裝置,它可以是包含含有多個行和列的行或多維陣列的集合的單個二維陣列。在lua中,陣列是使用索引表與整數實現的。陣列的大小是不固定的,它可以增長基於我們需要受儲存器限制。一維陣列 一維陣列可以用乙個簡單的表結構來表示,可以初始化,使用乙個簡單的for迴圈讀取。如下例子所示。複製 如下...

Lua 模組的概念(一)

模組原理 簡單來說,就是由變數等組成的 table,因此建立 模組本質就是建立了乙個 table,那麼最後這個 table 是需要進行返回的乙個值。模組的作用 類似於是乙個封裝庫,把一些公用的 放在乙個檔案裡面,以 api 介面的方式在其他的地方進行乙個呼叫,有利於 的重用和降低 耦合度。注意 使用...