本文講解了 lua 中長度運算子(#)的一些知識基礎(注: 以下討論基於 lua 5.3.5 版本)
lua 中的長度運算子(#)可以用於獲取 table 的"長度",舉個簡單的例子:
local t =
print(#t) -- 3
但其實對於 table 而言,長度運算子並不等同於獲取 table 的"長度",更準確一些的說法應該是獲取 table序列部分的長度,而所謂序列,是指索引為 1 至 n 的集合(中間不能有空元素),以上面的**為例,表(table) t 就是乙個序列, 索引為 1 至 3,所以表(table) t 的長度即為 3.
而對於下面的 表(table) t:
local t =
雖然表(table) t 有 4 個元素(索引為 1 至 4),但是索引 4 為空元素(nil),所以表(table) t 的序列部分索引是 1 至 3,所以表(table) t 的長度仍為 3:
local t =
print(#t) -- 3
在實際開發中,也並不建議在用作序列的 table 中插入空元素(nil),所以一般來講,能夠在用作序列的 table 上正確使用長度運算子(#),並且了解長度運算子(#)的侷限性(只能正確作用於序列上)就足夠了.
以下內容涉及實現細節,討論的示例也並不常見,僅想初步了解的朋友可以跳過閱讀,否則容易引起混淆高階
接著上面的例子,我們再來看下這段**:
local t =
print(#t) -- ?
按照之前的理解,似乎輸出應為 2(因為表(table) t 的序列部分索引為 1 至 2),但實際上,程式的輸出為 4:
local t =
print(#t) -- 4
原因在於 lua 的相關實現中,長度是從最大的陣列索引處開始查詢的,如果發現該處的元素不為空(nil),就直接向後查詢.
在上面的例子中, lua 首先檢查 t[4](t 的最大陣列索引為 4),發現不是空元素,於是直接向後查詢,發現不存在 t[5] 元素,於是便返回了 4(作為 table 的序列長度,下同).
我們接著來,考慮下面**:
local t =
print(#t) -- ?
按照之前的講解,現在表(table) t 的最大陣列索引處(t[6])為空元素,於是我們應該直接向前查詢 t[5],然後發現 t[5] 並不是空元素,於是返回 5.
但實際上,程式的輸出為 2:
local t =
print(#t) -- 2
原因在於當 lua 發現 table 最大陣列索引處的元素為空時,是按二分法的方式向前查詢的,當發現 t[6] 為空元素之後, lua 向前查詢的元素不是 t[5],而是 t[3],接著發現 t[3] 是空元素,於是從 t[3] 開始繼續向前二分查詢,最後返回了 2.
接著我們可以來做些練習了:
local t =
print(#t) -- ?
按照上面的解釋,我們很容易知道輸出應為 1:
local t =
print(#t) -- 1
接著我們進行賦值操作:
local t =
print(#t) -- 1
t[8] = 1
print(#t) -- ?
這時 table 的最大陣列索引處(t[8])不為空元素,按照先前的解釋,輸出會變成 8:
local t =
print(#t) -- 1
t[8] = 1
print(#t) -- 8
我們再進行一次賦值操作:
local t =
print(#t) -- 1
t[8] = 1
print(#t) -- 8
t[9] = 1
print(#t) -- ?
這個時候輸出為多少呢?你也許會猜測是 9,但實際上輸出為 1 !
local t =
print(#t) -- 1
t[8] = 1
print(#t) -- 8
t[9] = 1
print(#t) -- 1
原因在於我們最後一次的賦值操作因為新建了索引(之前不存在索引 9),繼而觸發了 table 的 rehash 流程,在這個流程中, lua 會根據 table 元素的分布重新調整陣列的大小,使的最後的輸出變為了 1(這裡我們不展開 rehash 的流程細節,有興趣深入的朋友可以看看 lua 原始碼中的 rehash 函式).
高階如果混合使用 table 中的 陣列部分 和 hash部分,則長度運算子(#)的結果會更加複雜一些:
local t =
print(#t) -- ?
當 lua 發現 table 的最大陣列索引處不為空元素時,其會繼續在 table 的 hash部分 尋找,繼而導致上面的輸出為 5:
local t =
print(#t) -- 5
另外, hash 部分的查詢流程也是二分進行的,這也導致以下**的輸出為 10(而上面**的輸出為 5) :
local t =
print(#t) -- 10
最後乙個例子有些隱晦,在此我們僅僅列出結果,有興趣了解原因的朋友可以看看 lua 原始碼中的 luao_int2fb 和 luao_fb2int 兩個函式:
local t =
print(#t) -- 18
local t =
print(#t) -- 1
總結
了解 lua 中長度運算子(#)的作用並不困難,但其中涉及的細節並不簡單(有時候甚至有些隱晦),有興趣深入的朋友可以從 lua 原始碼中的 luah_getn 函式開始探索.
移位運算子小知識
移位運算子它主要包括 左移運算子 無符號右移運算子 有符號右移運算子 移位運算子操作的物件就是二進位制的位,可以單獨用移位運算子來處理int型整數。左移運算子用 表示,是將運算子左邊的物件,向左移動運算子右邊指定的位數,並且在低位補0。其實,向左移n位,就相當乘上2的n次方。無符號右移運算子用 表示...
程式設計小知識之 自增 自減 運算子
本文講述了 c c 中 自增 自減 運算子 的一些知識 自增 自減 運算子應該是 c c 程式設計中的基礎知識了,而自增 自減 運算子又有兩種形式,分別是前置自增 自減 和後置自增 自減 出於簡單考慮,後文僅以自增運算子進行舉例講解 譬如表示式 i 和 i 就分別表示對 i 進行前置自增 和 對 i...
lua 範例 Lua 運算子
lua 運算子 運算子是乙個特殊的符號,用於告訴直譯器執行特定的數學或邏輯運算。lua提供了以下幾種運算子型別 算術運算子 關係運算子 邏輯運算子 其他運算子 算術運算子 下表列出了 lua 語言中的常用算術運算子,設定 a 的值為10,b 的值為 20 操作符描述例項 加法a b 輸出結果 30 ...