国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

Lua教程(十): 全局變量和非全局的環(huán)境

2024-07-21 23:04:45
字體:
供稿:網(wǎng)友

Lua將其所有的全局變量保存在一個常規(guī)的table中,這個table被稱為“環(huán)境”。它被保存在全局變量_G中。

1. 全局變量聲明:

Lua中的全局變量不需要聲明就可以使用。盡管很方便,但是一旦出現(xiàn)筆誤就會造成難以發(fā)現(xiàn)的錯誤。我們可以通過給_G表加元表的方式來保護(hù)全局變量的讀取和設(shè)置,這樣就能降低這種筆誤問題的發(fā)生幾率了。見如下示例代碼:

復(fù)制代碼 代碼如下:

--該table用于存儲所有已經(jīng)聲明過的全局變量名
local declaredNames = {}
local mt = {
    __newindex = function(table,name,value)
        --先檢查新的名字是否已經(jīng)聲明過,如果存在,這直接通過rawset函數(shù)設(shè)置即可。
        if not declaredNames[name] then
            --再檢查本次操作是否是在主程序或者C代碼中完成的,如果是,就繼續(xù)設(shè)置,否則報錯。
            local w = debug.getinfo(2,"S").what
            if w ~= "main" and w ~= "C" then
                error("attempt to write to undeclared variable " .. name)
            end
            --在實際設(shè)置之前,更新一下declaredNames表,下次再設(shè)置時就無需檢查了。
            declaredNames[name] = true
        end
        print("Setting " .. name .. " to " .. value)
        rawset(table,name,value)
    end,
   
    __index = function(_,name)
        if not declaredNames[name] then
            error("attempt to read undeclared variable " .. name)
        else
            return rawget(_,name)
        end
    end
}   
setmetatable(_G,mt)

 

a = 11
local kk = aa

--輸出結(jié)果為:
--[[
Setting a to 11
lua: d:/test.lua:21: attempt to read undeclared variable aa
stack traceback:
        [C]: in function 'error'
        d:/test.lua:21: in function <d:/test.lua:19>
        d:/test.lua:30: in main chunk
        [C]: ?
--]]

 

 2. 非全局的環(huán)境:

全局環(huán)境存在一個剛性的問題,即它的修改將影響到程序的所有部分。Lua 5為此做了一些改進(jìn),新的特征可以支持每個函數(shù)擁有自己獨(dú)立的全局環(huán)境,而由該函數(shù)創(chuàng)建的closure函數(shù)將繼承該函數(shù)的全局變量表。這里我們可以通過setfenv函數(shù)來改變一個函數(shù)的環(huán)境,該函數(shù)接受兩個參數(shù),一個是函數(shù)名,另一個是新的環(huán)境table。第一個參數(shù)除了函數(shù)名本身,還可以指定為一個數(shù)字,以表示當(dāng)前函數(shù)調(diào)用棧中的層數(shù)。數(shù)字1表示當(dāng)前函數(shù),2表示它的調(diào)用函數(shù),以此類推。見如下代碼:

 

復(fù)制代碼 代碼如下:

a = 1
setfenv(1,{})
print(a)

 

--輸出結(jié)果為:
--[[
lua: d:/test.lua:3: attempt to call global 'print' (a nil value)
stack traceback:
        d:/test.lua:3: in main chunk
        [C]: ?
--]]

 

為什么得到這樣的結(jié)果呢?因為print和變量a一樣,都是全局表中的字段,而新的全局表是空的,所以print調(diào)用將會報錯。

為了應(yīng)對這一副作用,我們可以讓原有的全局表_G作為新全局表的內(nèi)部表,在訪問已有全局變量時,可以直接轉(zhuǎn)到_G中的字段,而對于新的全局字段,則保留在新的全局表中。這樣即便是函數(shù)中的誤修改,也不會影響到其他用到全局變量(_G)的地方。見如下代碼:

復(fù)制代碼 代碼如下:

a = 1
local newgt = {}  --新環(huán)境表
setmetatable(newgt,{__index = _G})
setfenv(1,newgt)
print(a)  --輸出1

 

a = 10
print(a)  --輸出10
print(_G.a) --輸出1
_G.a = 20
print(a)  --輸出10

 

最后給出的示例是函數(shù)環(huán)境變量的繼承性。見如下代碼:

復(fù)制代碼 代碼如下:

function factory()
    return function() return a end
end
a = 3
f1 = factory()
f2 = factory()
print(f1())  --輸出3
print(f2())  --輸出3

 

setfenv(f1,{a = 10})
print(f1())  --輸出10
print(f2())  --輸出3


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 康保县| 夹江县| 花莲市| 清远市| 嘉善县| 吐鲁番市| 台中县| 潍坊市| 正蓝旗| 临安市| 南陵县| 噶尔县| 潍坊市| 运城市| 张家川| 五指山市| 光山县| 邢台县| 广宁县| 阳原县| 濮阳县| 会宁县| 咸阳市| 镇宁| 水城县| 泗阳县| 南昌市| 长泰县| 盐亭县| 子长县| 开远市| 门源| 越西县| 罗甸县| 金华市| 大港区| 贡觉县| 邵阳市| 自治县| 蓝田县| 多伦县|