## 輪詢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
```