有个体会, lua table 的 #操作 是针对 table.insert() / table.remove() 这一对操作的 “操作数维护”:
每次调用 table.insert() 都会是 #操作值增加(这是我自己的表达, 即使 用 #table 取得表的 返回值);
每次调用 table.remove() 都会减少 #操作值。
table 内部元素维护 有两种方式:
第一种是 使用 table.insert() / table.remove() 这一对
第二种是 使用 operator[]
另外, 采用默认值声明并定义表, 并且由positive key 时, lua引擎应该会“尝试”自动调用 table.insert() , 例如
local tb = { 11, 22, c33=33 }
我的假设过程是:
table.insert( tb, 11)
table.insert( tb, 22)
table.insert( tb, 33)
tb[ c33] = 33
有这么个假设 及 上述猜想后, 看如下例子:
local f = io.open( "out.out", "a" ) function trace( tb) f:write( "count of positive lements is ", #tb, "\n" ) for k, v in pairs( tb) do f:write( k, "\t", v, "\n") end end --=============================== create a table local tb = { 11, 22, c33=33 } trace( tb) --=============================== insert positive number elements for i = 1, 10, 1 do table.insert( tb, i) end trace( tb) --================================ add element with operator[] tb[ 88] = 88 trace( tb) --============================== remove elements with nil to operaor[] for i = 1, 3, 1 do tb[ i] = nil end trace( tb) --============================== remove elements with table.remove() for i = 1, 3, 1 do table.remove( tb, 1) end trace( tb) --=============================== add element with operator[] tb[ 98] = 98 trace( tb) f:write( table.maxn( tb) , "\n") f:flush() f:close()
输入结果将会是 out.out:
count of positive lements is 2 1 11 2 22 c33 33 count of positive lements is 12 1 11 2 22 3 1 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 12 10 c33 33 count of positive lements is 12 1 11 2 22 3 1 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 12 10 88 88 c33 33 count of positive lements is 12 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 12 10 88 88 c33 33 count of positive lements is 9 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 88 88 c33 33 count of positive lements is 9 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 88 88 98 98 c33 33 98
过程分析如下:
local f = io.open( "out.out", "a" ) function trace( tb) f:write( "count of positive lements is ", #tb, "\n" ) for k, v in pairs( tb) do f:write( k, "\t", v, "\n") end end --=============================== create a table local tb = { 11, 22, c33=33 } trace( tb) --[[ 按照上述假设 #操作值 为 2 count of positive lements is 2 1 11 2 22 c33 33 ]] --=============================== insert positive number elements for i = 1, 10, 1 do table.insert( tb, i) end trace( tb) --[[ 这里增加调用了 10次的 table.insert() count of positive lements is 12 1 11 2 22 3 1 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 12 10 c33 33 ]] --================================ add element with operator[] tb[ 88] = 88 trace( tb) --[[ operator[] 维护表内元素, 并不会修改 #操作值 count of positive lements is 12 1 11 2 22 3 1 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 12 10 88 88 c33 33 ]] --============================== remove elements with nil to operaor[] for i = 1, 3, 1 do tb[ i] = nil end trace( tb) --[[ operator[] 维护表元素, 并不会修改 #操作值 count of positive lements is 12 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 12 10 88 88 c33 33 ]] --============================== remove elements with table.remove() for i = 1, 3, 1 do table.remove( tb, 1) end trace( tb) --[[ 3次 table.remove() 操作, 减少 #操作值 count of positive lements is 9 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 88 88 c33 33 ]] --=============================== add element with operator[] tb[ 98] = 98 trace( tb) --[[ 又一次的 operator[] 操作, 并不会修改 #操作值 count of positive lements is 9 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 88 88 98 98 c33 33 ]] f:write( table.maxn( tb) , "\n") -- 98 f:flush() f:close()
小结:
1.由于 lua table的元素的维护 分为 table.insert() / remove() 与 operator[] 两套实现机制, 在相对脚本语言, 尤其是项目多人协作、分时段开发时, 很容易产生 2*2 = 4中以上的 table表 元素维护方式, 容易造成混乱, 造成数据不安全问题。 是否应该对那些 涉及需要被 “多处”的 共享table 表 的操作进行 封装。
2.一个应用, 假如上述成立, 在新增数据时 统一用 table.insert() 带来简便, 并获取“流水号id”:
local tb = {} function InsertTable( container, item ) table.insert( container, item) item.seqno = #container end
不然 直接的 operator[key] = item 得事先确定 key 值; 而在删除元素时, 不适用 table.remove() 而是用 operator[]:
--未考虑 nil 的key 判断 function RemoveByKey( container, key ) container[ key] = nil end function RemoveByItem( container, item ) container[ item.seqno] = nil end
这样可保证在 container 的 #操作值 只递增, 是一个 “流水号”。