此第一版是針對 Lua 5.0 編寫的。雖然在很大程度上仍然適用於後續版本,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買本書,您也可以 支援 Lua 專案


12.1.2 – 儲存有循環的表格

若要處理具有共用拓撲(即有循環和共用子表格)的表格,我們需要不同的方法。建構函式無法表示此類表格,因此我們不會使用它們。若要表示循環,我們需要名稱,因此我們的下一個函式將取得要儲存的值及其名稱作為引數。此外,我們必須追蹤已儲存表格的名稱,以便在偵測到循環時重複使用它們。我們將使用一個額外表格來進行此追蹤。此表格將有表格作為索引,並將其名稱作為關聯的值。

我們將維持一個限制,即我們要儲存的表格只具有字串或數字作為鍵。下列函式會序列化這些基本類型,並傳回結果

    function basicSerialize (o)
      if type(o) == "number" then
        return tostring(o)
      else   -- assume it is a string
        return string.format("%q", o)
      end
    end
下一個函式會執行困難的工作。saved 參數是追蹤已儲存表格的表格
    function save (name, value, saved)
      saved = saved or {}       -- initial value
      io.write(name, " = ")
      if type(value) == "number" or type(value) == "string" then
        io.write(basicSerialize(value), "\n")
      elseif type(value) == "table" then
        if saved[value] then    -- value already saved?
          io.write(saved[value], "\n")  -- use its previous name
        else
          saved[value] = name   -- save name for next time
          io.write("{}\n")     -- create a new table
          for k,v in pairs(value) do      -- save its fields
            local fieldname = string.format("%s[%s]", name,
                                            basicSerialize(k))
            save(fieldname, v, saved)
          end
        end
      else
        error("cannot save a " .. type(value))
      end
    end
舉例來說,如果我們建立一個表格,如下所示
    a = {x=1, y=2; {3,4,5}}
    a[2] = a    -- cycle
    a.z = a[1]  -- shared sub-table
則呼叫 save('a', a) 會將其儲存如下
    a = {}
    a[1] = {}
    a[1][1] = 3
    a[1][2] = 4
    a[1][3] = 5
    
    a[2] = a
    a["y"] = 2
    a["x"] = 1
    a["z"] = a[1]
(這些指派的實際順序可能會有所不同,因為它取決於表格遍歷。不過,此演算法會確保在新的定義中需要的任何先前節點都已定義。)

如果我們要儲存具有共用部分的數個值,我們可以使用相同的 saved 表格對 save 進行呼叫。例如,如果我們建立下列兩個表格,

    a = {{"one", "two"}, 3}
    b = {k = a[1]}
並將它們儲存如下,
    save('a', a)
    save('b', b)
結果將沒有共用部分
    a = {}
    a[1] = {}
    a[1][1] = "one"
    a[1][2] = "two"
    a[2] = 3
    b = {}
    b["k"] = {}
    b["k"][1] = "one"
    b["k"][2] = "two"
但是,如果我們對每個 save 呼叫使用相同的 saved 表格,
    local t = {}
    save('a', a, t)
    save('b', b, t)
則結果將共用共用部分
    a = {}
    a[1] = {}
    a[1][1] = "one"
    a[1][2] = "two"
    a[2] = 3
    b = {}
    b["k"] = a[1]

如同在 Lua 中常見的,有許多其他替代方案。其中,我們可以在不給予其全域名稱的情況下儲存一個值(取而代之的是,區塊會建立一個區域值並傳回它);我們可以處理函式(透過建立一個將每個函式關聯至其名稱的表格)等。Lua 賦予您力量;您建立機制。