## 輪詢table中有nil而被中斷 有時候使用foreach來輪詢table的時候,有可能遇到後面的成員沒有被輪到的問題。例如: ``` lua local tb = {1, 2, nil, 4, 5} for idx, val in ipairs(tb) do print(val) end -- 結果: -- 1 -- 2 ``` 是因為lua在輪詢時,遇到nil後就會中斷,無法判斷這個成員本身是不是nil。 所以需要: 1. 以別的for方式輪詢 ``` lua local tb = {1, 2, nil, 4, 5} for idx = 1, #tb do print(tb[idx]) end ``` 2. 以其他值代替nil --- ## 偽繼承的成員存取混淆問題 有時候使用setmetatable 以及 __index 來實現類似繼承效果時,會造成非預期的變數設置問題。 首先若以這樣的方式來實現繼承效果: ``` lua -- 某一種繼承實現方式 function Inst:new (o) o = o or {} setmetatable(o, self) self.__index = self return o end ``` 會使被new出來的 空table,在取得任意成員時,因為找不到非nil的值,而會去__index中,也就是意義上的父table去尋找。 而設置時,則是在該空table中加入key value,並且讓之後要取得時是直接由此取得,也就不用進到__index中。 但是這樣做會有一些狀況,如: 1. 若子table覆寫了某一成員為nil,但父table依然存有該成員的值,那麼在對子table進行取用時,則會因為該nil而轉而向__index去從父table中取值。 ``` lua local Inst = { val = 5 } -- 某一種繼承實現方式 function Inst:new (o) o = o or {} setmetatable(o, self) self.__index = self return o end local subInst = Inst:new() print(subInst.val) -- result: 5 subInst.val = nil print(subInst.val) -- result: 5 ``` 2. 若在進行子table覆寫其中的table成員時,不是直接採用 = 來設置取代,而是將該table成員傳入其他如table.insert來使用的話,就會因為原本的子table因為是空table,所以取用來設置的反而是透過__index取得的父table中的table成員。導致可能有的資料誤用問題。 ``` lua local Inst = { val = {"original"} } -- 某一種繼承實現方式 function Inst:new (o) o = o or {} setmetatable(o, self) self.__index = self return o end -- 建立兩個子Table local subInst_A = Inst:new() local subInst_B = Inst:new() -- 對 子Table A 進行加入(但實際上被取用來設置的是Inst.val) subInst_A.val[2] = "A" -- 對 子Table B 進行加入(但實際上被取用來設置的是Inst.val) table.insert(subInst_B.val, "B") -- 印出 subInst_B.val 但實際上會取到 Inst.val for idx, val in ipairs(subInst_B.val) do print(val) end -- result: original, A, B ```