Lua語言基礎匯總(10) -- Lua中的環境概念

來源:互聯網
上載者:User

標籤:style   http   color   使用   os   io   strong   資料   

前言

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

1 for n in pairs(_G) do print(n) end

 

在你的電腦上運行一下以上代碼,看看結果。

 

全域變數聲明

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

12345678910 setmetatable(_G, {      __newindex = function (_, k)           error("Attempt to write to undeclared variable " .. k)      end,      __index = function (_, k)           error("Attempt to read undeclared variable " .. k)      end })   print(a) -- 這裡a就是一個全域變數

 

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

 

非全域的變數

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

 

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

12345 a = 1 -- 這裡建立了一個全域變數   -- 將當前環境變數改為一個新的空table setfenv(1, {}) print(a)

 

運行代碼會彈出這樣的錯誤:attempt to call global ‘print’ (a nil value)

 

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

123456 a = 1 -- 這裡建立了一個全域變數   -- 將當前環境變數改為一個新的空table setfenv(1, {g = _G}) g.print(a)          -- 輸出nil g.print(g.a)     -- 輸出1

 

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

123456 a = 1 -- 這裡建立了一個全域變數   -- 將當前環境變數改為一個新的空table setfenv(1, {_G = _G}) _G.print(a)          -- 輸出nil _G.print(_G.a)     -- 輸出1

 

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

12345678 a = 1 -- 這裡建立了一個全域變數   local newEnv = {} setmetatable(newEnv, {__index = _G})   -- 將當前環境變數改為一個新的空table setfenv(1, newEnv) print(a)

 

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

 

來源網址:http://www.jellythink.com/archives/522

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.