標籤:des 使用 for ar art 代碼 amp size
稀疏數組的長度返回的不對,不知道算不算是個 bug?(在 Lua5.2.2 中測試的)
如果一個表容量一半的元素,用 ‘#‘ 取長度取的不對。但是對於小於容量一半的情況,表現的是對的。
根據 Lua 的代碼實現,‘#’號取表長度時取得是表中第一個空元素前的那個位置。
原文是(luaH_getn 注釋) :
Try to find a boundary in table `t‘. A `boundary‘ is an integer index such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
看下例子:
a = {}for i = 1, 2 do a[i] = i*3enda[4] = 811
用 #a 取得的結果是 4,而根據上面的描述應該取回 2。
再如:
for i = 1, 4 do a[i] = i*3enda[8] = 811
用 #a 取得的結果是 8,而根據上面的描述應該取回 4。
在老一點的版本裡可以用 table.maxn 取最大下標,新版本裡這個介面被廢除了。
簡單的分析下原因,當表中的元素很少而下標的跨度很大時,也就是對於很稀疏的數組,儲存的時候存在表的雜湊部分。但當數組不是那麼稀疏的時候,就存在了數組部分,就是按下標從 1 遞增而來。這也是對空間使用的一種最佳化。
看下取長度的實現(只截取對分析有用的部分)
unsigned int j = t->sizearray;if (j > 0 && ttisnil(&t->array[j - 1])) { // some codes}/* else must find a boundary in hash part */else if (isdummy(t->node)) /* hash part is empty? */ return j; /* that is easy... *///some other codes
注意 if 裡後面的那個表最後的一個元素判空操作,此時對於上面的兩段代碼 a[4] 或 a[8],剛好它們位於數組的最後一個元素,所以不是空,if 裡面不執行。由於這裡的表沒有雜湊部分,所以,到 else if 裡直接返回表長,也就是上面看到的 4 或 8。
不過,實際中,對於稀疏數組不要用 ‘#‘ 取長度,因為這個操作沒有什麼意義。