一:Lua多重繼承

二:Lua私密性

三:弱引用Table


一:Lua多重繼承

Lua的繼承就是在元表裡面查找自己不存在的欄位。單繼承我們在前面已經講過,就是在元表裡面查找自己不存在的欄位。下面我們研究一下多繼承。

多繼承無非就是在多個table中查找某個欄位而已。Lua里的繼承就是在別人的table里 查找自己不存在的欄位。

那麼,單繼承與多重繼承的差別也在這裡,一個是只查找一個table,另一個是查找兩 個或以上的table。下面我們看一下下面的查找函數。

這裡的classes參數,是一個table,這個table里又存放了多個table,也就是我們想要繼承的那些類。而key就是要查找的欄位。只需要遍歷所有的table,判斷這個欄位是否在 某個table里,找到之後,就返回這個值。

創建繼承多個類的子類,下面我們創建一個繼承多個table的表,如下代碼所示:

createClass函數就是用來創建一個繼承了多個類的子類,我們分析如下:

1) 參數是一個可變參數,我們要將多個被繼承的類作為參數傳遞進來

2) parents用於保存這些被繼承的類

3) 創建一個新的table——child,它就是我們想要的那個繼承了多個類的子類

4) 給child設置元表,並且設置__index元方法,__index元方法可以是一個函數,當它 是一個函數時,它的參數就是元表所屬的table,以及要查找的欄位名。 5) 我們在__index元方法函數里調用search函數,從多個父類中查找所需的欄位。於 是,當調用child的某個函數時,就會從各個父類中查找,這已經完成了繼承的工作了。 6) 聲明new函數,並且最後返回child,一切都完成了。

測試代碼如下:

二:Lua私密性

對於C++語言,我們都很熟悉,public、private、protected關鍵詞,保護了某些變 量的訪問許可權。然而,Lua里是沒有 private 這種說法的,類也是一個table,table的 所有欄位都是可以調用的,並沒有說哪些是公有的,哪些是私有的。

如果有某些函數和屬性不希望被外部調用,我們可以這樣實現:

測試代碼如下:

local sp = createTSprite();

sp.hello();

sp.hi();

調用createTSprite函數後,會返回一個新的 table,

這個table僅僅存放了一些欄位,這些欄位

就是能夠被外部直接調用的函數或者屬性。

三:弱引用Table

Lua使用基於被內置在Lua某些演算法的垃圾收集自動內存管理。可以自動內存管理的結果,作為一個開發者:

? 沒有必要擔心的對象分配內存。

? 無需釋放他們時,不再需要可將其設置為nil。

問題就出現在,什麼對象才是垃圾對象,有些時候,我們很清楚某個對象是垃圾, 但是,Lua卻無法發現。如下代碼所示:

雖然我們在給t賦值之後,key1 和key2都賦值為nil了。

但是,已經添加到table中的key 值是不會因此而被當做垃圾的。

換句話說,key1本身已經是nil 值,但它曾經所指向的內容依然存放在t中。key2也是一樣的情況。 所以我們最後還是能輸出key1和 key2的name欄位。

那麼,如果我們把某個table作為另一個table的key值後,希望當table設為nil值 時,另一個table的那一條欄位也被刪除。應該如何實現?

這時候就要用到弱引用table了,弱引用table的實現也是利用了元表。 我們將上面 的例子稍微修改如下:

這就是弱引用table的其中一種, 給table添加__mode元方法,如果這個元方法的值包含了字元串」k」, 就代表這個table的key都是弱引用的。

一旦其他地方對於key值的引用取消了(設置為nil),那麼,這個table里的這個欄位也會被刪除。

通俗地說,因為t的key被設置為弱引用,所以,執行t[key1] = 1後,t 中確實存在這個欄位。

隨後,又執行了key1 = nil,此 時,除了t本身以外,就沒有任何地 方對key1保持引用,所以t的key1字 段也會被刪除。

對於弱引用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執行垃圾回收的時候,並不一定是立刻生效的。


推薦閱讀:
相关文章