這次要介紹的內容比較少,就一個——弱引用table
1.無法超越人類智慧的智能——自動內存管理的缺陷
我們都知道,Lua是具備自動內存管理的,好吧,也許有些朋友不知道。
我們只管創建對象,無須刪除對象(當然,對于不要的對象你需要設置一下nil值),Lua會自動刪除那些被認為是垃圾的對象。
問題就出現在,什么對象才是垃圾對象,有些時候,我們很清楚某個對象是垃圾,但是,Lua卻無法發現。
比如這樣一個例子:
這段代碼有點復雜,智商低于250的可能會看不懂。
首先以一個table,叫做t。
然后創建一個新的table——key1,這個key1作為t的key值,給t新增了一個字段,賦值為1。
同樣的,key2也作為t的一個key值。
接著,調用了collectgarbage函數,可以不管它,我們只要知道,它會讓lua進行一次垃圾回收。
最后輸出t的所有字段,輸出結果如下:
但是,已經添加到table中的key值是不會因此而被當做垃圾的。
換句話說,key1本身已經是nil值,但它曾經所指向的內容依然存放在t中。key2也是一樣的情況。
所以我們最后還是能輸出key1和key2的name字段。
2.顛覆你的認知——弱引用table
剛剛舉例的只是正常情況,那么,如果我們把某個table作為另一個table的key值后,希望當table設為nil值時,另一個table的那一條字段也被刪除。
應該如何實現?
這時候就要用到弱引用table了,弱引用table的實現也是利用了元表。
我們來看看下面的代碼,和之前幾乎一樣,只是加了一句代碼:
留意,在t被創建后,立刻給它設置了元表,元表里有一個__mode字段,賦值為”k”字符串。
如果這個時候大家運行代碼,會發現什么都沒有輸出,因為,t的所有字段都不存在了。
這就是弱引用table的其中一種,給table添加__mode元方法,如果這個元方法的值包含了字符串”k”,就代表這個table的key都是弱引用的。
一旦其他地方對于key值的引用取消了(設置為nil),那么,這個table里的這個字段也會被刪除。
通俗地說,因為t的key被設置為弱引用,所以,執行t[key1] = 1后,t中確實存在這個字段。
隨后,又執行了key1 = nil,此時,除了t本身以外,就沒有任何地方對key1保持引用,所以t的key1字段也會被刪除。
3.三種形式的弱引用
對于弱引用table,其實有三種形式:
1)key值弱引用,也就是剛剛說到的情況,只要其他地方沒有對key值引用,那么,table自身的這個字段也會被刪除。設置方法:setmetatable(t, {__mode = “k”});
2)value值弱引用,情況類似,只要其他地方沒有對value值引用,那么,table的這個value所在的字段也會被刪除。設置方法:setmetatable(t, {__mode = “v”});
3)key和value弱引用,規則一樣,但是key和value都同時生效,任意一個起作用時都會導致table的字段被刪除。設置方法:setmetatable(t, {__mode = “kv”});
當然,這里所說的被刪除,是指在Lua執行垃圾回收的時候,并不一定是立刻生效的。
我們剛剛只是為了測試,而強制執行了垃圾回收。
4.結束
好了,這次的內容比較少,其實書上有蠻多關于弱引用的例子的。
關于Lua的最基礎部分,到這里算是結束了。
后面的內容是一些庫的介紹,以及更深入的一些內容(C和Lua間調用、自定義類型、線程、內存管理)。
接下來可能會放緩文章更新速度,因為好多庫的介紹,不知道有沒有必要用文章記錄下來。
可能而已~
|
新聞熱點
疑難解答