table.getn(t) 等價(jià)于 #t 但計(jì)算的是數(shù)組元素,不包括 hash 鍵值。而且數(shù)組是以第一個(gè) nil 元素來判斷數(shù)組結(jié)束。#
只計(jì)算 array 的元素個(gè)數(shù),它實(shí)際上調(diào)用了對象的 metatable 的 __len
函數(shù)。對于有 __len
方法的函數(shù)返回函數(shù)返回值,不然就返回?cái)?shù)組成員數(shù)目。
Lua 中,數(shù)組的實(shí)現(xiàn)方式其實(shí)類似于 C++ 中的 map,對于數(shù)組中所有的值,都是以鍵值對的形式來存儲(無論是顯式還是隱式),Lua 內(nèi)部實(shí)際采用哈希表和數(shù)組分別保存鍵值對、普通值,所以不推薦混合使用這兩種賦值方式。尤其需要注意的一點(diǎn)是:Lua 數(shù)組中允許 nil 值的存在,但是數(shù)組默認(rèn)結(jié)束標(biāo)志卻是 nil。這類比于 C 語言中的字符串,字符串中允許 '\0' 存在,但當(dāng)讀到 '\0' 時(shí),就認(rèn)為字符串已經(jīng)結(jié)束了。
初始化是例外,在 Lua 相關(guān)源碼中,初始化數(shù)組時(shí)首先判斷數(shù)組的長度,若長度大于 0 ,并且最后一個(gè)值不為 nil,返回包括 nil 的長度;若最后一個(gè)值為 nil,則返回截至第一個(gè)非 nil 值的長度。
注意:一定不要使用 #
操作符或 table.getn
來計(jì)算包含 nil 的數(shù)組長度,這是一個(gè)未定義的操作,不一定報(bào)錯,但不能保證結(jié)果如你所想。如果你要刪除一個(gè)數(shù)組中的元素,請使用 remove 函數(shù),而不是用 nil 賦值。
-- test.lua
local tblTest1 = { 1, a = 2, 3 }
print("Test1 " .. #(tblTest1))
local tblTest2 = { 1, nil }
print("Test2 " .. #(tblTest2))
local tblTest3 = { 1, nil, 2 }
print("Test3 " .. #(tblTest3))
local tblTest4 = { 1, nil, 2, nil }
print("Test4 " .. #(tblTest4))
local tblTest5 = { 1, nil, 2, nil, 3, nil }
print("Test5 " .. #(tblTest5))
local tblTest6 = { 1, nil, 2, nil, 3, nil, 4, nil }
print("Test6 " .. #(tblTest6))
我們分別使用 Lua 和 LuaJIT 來執(zhí)行一下:
? luajit test.lua
Test1 2
Test2 1
Test3 1
Test4 1
Test5 1
Test6 1
? lua test.lua
Test1 2
Test2 1
Test3 3
Test4 1
Test5 3
Test6 1
這一段的輸出結(jié)果,就是這么 匪夷所思。不要在 Lua 的 table 中使用 nil 值,如果一個(gè)元素要刪除,直接 remove,不要用 nil 去代替。