Lua 表格大小

lua-users home
wiki


[!] 版本公告:本文中描述的問題已得到解決。從 5.0 版開始,n 值不再作為表格列表部分的大小計算中所引用的內容。

問題

表格包含成員「n」,作為表格插入的優化。也就是說,取自手冊:

getn (table)
視為列表時,傳回表格的大小。如果表格有數值值的 n 欄位,該值即為表格的大小。否則,大小即為表格中具有非 nil 值的最大數值索引。可以使用 Lua 定義此函數
function getn (t)
  if type(t.n) == "number" then return t.n end
  local max = 0
  for i, _ in t do
    if type(i) == "number" and i>max then max=i end
  end
  return max
end

由於表格的雙重特性,也就是可以同時作為列表和字典,因此「n」可能會與表格中的使用者資料相衝突。以下部分會列出一些問題解決方案。歡迎在解決方案旁留言或提出您自己的見解。請留下您的姓名或縮寫,以便計算「投票」。

這可以用更好的方式定義。n 欄位並非「表格大小」,也非用於「表格插入」。(事實上,Lua API 函數名稱及其說明文件讓這件事變得更令人困惑。)在 Lua 中,表格是純粹的資料類型,而列表並非如此。有許多種方法可以在表格資料類型上實作列表。由於列表是重要的資料類型,而且甚至在 VM 內部也是必需的 (用於變長引數),因此標準程式庫提供實作,其中包括使用 n 欄位來表示列表大小,以及演算法以設定任意表格的「列表部分」(當沒有 n 欄位時,getn 便會執行此動作)。

其他解決方案

這不是問題,別管它。

您的程式設計風格可能不需要在同一個表格中混合列表和字典,所以這可能不是問題。

因此,基本上您不想要破壞向後相容性,您會發現由於表大小名稱為「n」,任何衝突錯誤都容易找到,而且您不介意表格大小始終稱為「n」。為什麼不移除問題,正如您所說,「遲早會造成您困擾」,您可以在命名方面保持彈性?我不記得看過任何使用 n 設定表大小的程式碼(因此沒有向後的問題?)。--NDT

我認為這麼摘要就夠了 :-)。如果將表用作向量,我不會將其用作字典,儘管我可能在其中放入自己的鍵。在這種情況下,我根本不會使用鍵 n 或任何數字鍵。這與將鍵放入實作為表的任何物件中沒有什麼不同;您必須避免使用物件定義的鍵,希望這些鍵有文件記錄。事實上,我確實有使用 n 設定表大小的程式碼——除非您看過存在的每一行 Lua 程式碼,否則我不認為您可以輕率地宣稱沒有向後問題。在任何情況下,我認為使用 vec.n 而不是 getn(vec)檢索表大小很常見,因為如果您能確保該鍵存在(甚至 vec.n or getn(vec)),這樣會顯著加快速度。—— RiciLake

「希望有文件記錄」 :-) 可以避免這種混淆。表是多用途的這個事實,可以用作清單或字典,這表示不應套用此類型的限制。就我個人而言,我寧願修復可能因這個限制而損壞的程式碼。我認為 Lua 作為一種語言還處於起步階段,它的根源在於便利的嵌入和組態。它仍然有一些小怪癖,例如這個問題,在被視為嚴肅的指令碼語言之前,必須將其徹底解決。我不確定成為「Python 打敗者」是否是一個設計目標,但我確信作者渴望看到這門語言及其使用者群體的發展。隨著 Lua 的改進,這將持續發生。 :-) --NDT

公平地說,還有幾個其他地方,其中之一是 call。然而,撰寫取代函式絕對夠容易,而且沒有人強迫您使用 tinsert 和 tremove—— RiciLake

它應該重新命名

「n」變數應重新命名為較不容易衝突的變數,例如「__n__」

setn()

setn() 將會是搭配 getn() 的一個較好的解決方案。

len[t]

        settagmethod(tag({}), "index",
              function(v, k) if k == "n" then return len[v] end end)

因此,我願意改變我的投票 --RiciLake

這也與「getn」及「setn」相容;如果那是你想要的,只要包含

        function getn(v) return len[v] end
        function setn(v, n) len[v] = n end

請新增任何其他解決方案...

實作無法被覆寫的 getnEx() 函數

function getn (t)
  if type(t.n) == "number" then return t.n end
  return getnEx(t) -- internal function
end
如此一來,人們就能忽略令他們困擾的 getn() 功能,並改用不需要解決方法的 getnEx() 功能。getnEx() 實質上等於
function getnEx (t)
  local max = 0
  for i, _ in t do
    if type(i) == "number" and i>max then max=i end
  end
  return max
end

--Paul Hsieh

已投選票

請更新下方清單。如果你偏好匿名投票,只需在下方新增一票即可(但我們很樂於聽聽你的意見 :-)。


最近變更 · 偏好設定
編輯 · 歷程
上次編輯於 2019 年 3 月 8 日,下午 10:27 (GMT) (比對)