這次要介紹的內(nèi)容比較少,就一個(gè)——弱引用table
1.無法超越人類智慧的智能——自動(dòng)內(nèi)存管理的缺陷
我們都知道,Lua是具備自動(dòng)內(nèi)存管理的,好吧,也許有些朋友不知道。
我們只管創(chuàng)建對(duì)象,無須刪除對(duì)象(當(dāng)然,對(duì)于不要的對(duì)象你需要設(shè)置一下nil值),Lua會(huì)自動(dòng)刪除那些被認(rèn)為是垃圾的對(duì)象。
問題就出現(xiàn)在,什么對(duì)象才是垃圾對(duì)象,有些時(shí)候,我們很清楚某個(gè)對(duì)象是垃圾,但是,Lua卻無法發(fā)現(xiàn)。
比如這樣一個(gè)例子:
復(fù)制代碼 代碼如下:
t = {};
-- 使用一個(gè)table作為t的key值
key1 = {name = "key1"};
t[key1] = 1;
key1 = nil;
-- 又使用一個(gè)table作為t的key值
key2 = {name = "key2"};
t[key2] = 1;
key2 = nil;
-- 強(qiáng)制進(jìn)行一次垃圾收集
collectgarbage();
for key, value in pairs(t) do
print(key.name .. ":" .. value);
end
這段代碼有點(diǎn)復(fù)雜,智商低于250的可能會(huì)看不懂。
首先以一個(gè)table,叫做t。
然后創(chuàng)建一個(gè)新的table——key1,這個(gè)key1作為t的key值,給t新增了一個(gè)字段,賦值為1。
同樣的,key2也作為t的一個(gè)key值。
接著,調(diào)用了collectgarbage函數(shù),可以不管它,我們只要知道,它會(huì)讓lua進(jìn)行一次垃圾回收。
最后輸出t的所有字段,輸出結(jié)果如下:
復(fù)制代碼 代碼如下:
[LUA-print] key1:1
[LUA-print] key2:1
這很符合常理,也在我們的預(yù)計(jì)當(dāng)中,雖然我們?cè)诮ot賦值之后,key1和key2都賦值為nil了。
但是,已經(jīng)添加到table中的key值是不會(huì)因此而被當(dāng)做垃圾的。
換句話說,key1本身已經(jīng)是nil值,但它曾經(jīng)所指向的內(nèi)容依然存放在t中。key2也是一樣的情況。
所以我們最后還是能輸出key1和key2的name字段。
2.顛覆你的認(rèn)知——弱引用table
剛剛舉例的只是正常情況,那么,如果我們把某個(gè)table作為另一個(gè)table的key值后,希望當(dāng)table設(shè)為nil值時(shí),另一個(gè)table的那一條字段也被刪除。
應(yīng)該如何實(shí)現(xiàn)?
這時(shí)候就要用到弱引用table了,弱引用table的實(shí)現(xiàn)也是利用了元表。
我們來看看下面的代碼,和之前幾乎一樣,只是加了一句代碼:
復(fù)制代碼 代碼如下:
t = {};
-- 給t設(shè)置一個(gè)元表,增加__mode元方法,賦值為“k”
setmetatable(t, {__mode = "k"});
-- 使用一個(gè)table作為t的key值
key1 = {name = "key1"};
t[key1] = 1;
key1 = nil;
-- 又使用一個(gè)table作為t的key值
key2 = {name = "key2"};
t[key2] = 1;
key2 = nil;
-- 強(qiáng)制進(jìn)行一次垃圾收集
collectgarbage();
for key, value in pairs(t) do
print(key.name .. ":" .. value);
end
留意,在t被創(chuàng)建后,立刻給它設(shè)置了元表,元表里有一個(gè)__mode字段,賦值為”k”字符串。
如果這個(gè)時(shí)候大家運(yùn)行代碼,會(huì)發(fā)現(xiàn)什么都沒有輸出,因?yàn)?,t的所有字段都不存在了。
這就是弱引用table的其中一種,給table添加__mode元方法,如果這個(gè)元方法的值包含了字符串”k”,就代表這個(gè)table的key都是弱引用的。
一旦其他地方對(duì)于key值的引用取消了(設(shè)置為nil),那么,這個(gè)table里的這個(gè)字段也會(huì)被刪除。
通俗地說,因?yàn)閠的key被設(shè)置為弱引用,所以,執(zhí)行t[key1] = 1后,t中確實(shí)存在這個(gè)字段。
隨后,又執(zhí)行了key1 = nil,此時(shí),除了t本身以外,就沒有任何地方對(duì)key1保持引用,所以t的key1字段也會(huì)被刪除。
3.三種形式的弱引用
對(duì)于弱引用table,其實(shí)有三種形式:
1)key值弱引用,也就是剛剛說到的情況,只要其他地方?jīng)]有對(duì)key值引用,那么,table自身的這個(gè)字段也會(huì)被刪除。設(shè)置方法:setmetatable(t, {__mode = “k”});
2)value值弱引用,情況類似,只要其他地方?jīng)]有對(duì)value值引用,那么,table的這個(gè)value所在的字段也會(huì)被刪除。設(shè)置方法:setmetatable(t, {__mode = “v”});
3)key和value弱引用,規(guī)則一樣,但是key和value都同時(shí)生效,任意一個(gè)起作用時(shí)都會(huì)導(dǎo)致table的字段被刪除。設(shè)置方法:setmetatable(t, {__mode = “kv”});
當(dāng)然,這里所說的被刪除,是指在Lua執(zhí)行垃圾回收的時(shí)候,并不一定是立刻生效的。
我們剛剛只是為了測(cè)試,而強(qiáng)制執(zhí)行了垃圾回收。
4.結(jié)束
好了,這次的內(nèi)容比較少,其實(shí)書上有蠻多關(guān)于弱引用的例子的。
關(guān)于Lua的最基礎(chǔ)部分,到這里算是結(jié)束了。
后面的內(nèi)容是一些庫的介紹,以及更深入的一些內(nèi)容(C和Lua間調(diào)用、自定義類型、線程、內(nèi)存管理)。
接下來可能會(huì)放緩文章更新速度,因?yàn)楹枚鄮斓慕榻B,不知道有沒有必要用文章記錄下來。
可能而已~
您可能感興趣的文章:- Lua的table庫函數(shù)insert、remove、concat、sort詳細(xì)介紹
- Lua中table的幾種構(gòu)造方式詳解
- Lua中對(duì)table排序?qū)嵗?/li>
- Lua中遍歷數(shù)組和table的4種方法
- Lua中的metatable詳解
- Lua中的table學(xué)習(xí)筆記
- Lua中使用table.concat連接大量字符串實(shí)例
- Lua中的table淺析
- 獲取Lua表結(jié)構(gòu)(table)數(shù)據(jù)實(shí)例
- Lua Table轉(zhuǎn)C# Dictionary的方法示例