複製表格

lua-users home
wiki

Lua 標準程式庫沒有提供複製表格的函式。不過要實作此類函式相對簡單。

無法保證一般性的 table.copy 函式適用於所有案例,因為對於特定情況,必須選擇許多不同的面向。例如:共用或複製元表?是否要檢查使用者資料是否有 __copy 元方法?開發人員必須詢問並回答這些問題(以及許多其他問題)。

niektóre 「延伸標準程式庫」例如 Penlight 和 stdlib 為了方便而提供現成的複製函式。在實作自己的函式之前,請檢查它們是否適合你的案例。

以下函式提供一個作為基礎的工作

Quick & Dirty

function table.clone(org)
  return {table.unpack(org)}
end

local abc = {5,12,1}
local def = table.clone(abc)
table.sort(def)
print(abc[2], def[2]) -- 12	5

淺層複製

這是個簡單的簡陋實作。它只複製頂層值及其直接子項;不會處理更深的子項、元表或使用者資料或協程等特殊類型。它也容易受到 __pairs 元方法的影響。

function shallowcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in pairs(orig) do
            copy[orig_key] = orig_value
        end
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

深層複製

深層複製會複製所有層級(或層級的特定子集)。

以下是一個簡單的遞迴實作,另外還處理元表並避免 __pairs 元方法。

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, deepcopy(getmetatable(orig)))
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

透過對程式碼進行一些輕微的編輯,也可以建立一個支援遞迴表格的 deepcopy 函式版本。這樣做的方式是建立一個已複製表格的表格,並將其作為第二個引數提供給 deepcopy 函式。

-- Save copied tables in `copies`, indexed by original table.
function deepcopy(orig, copies)
    copies = copies or {}
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        if copies[orig] then
            copy = copies[orig]
        else
            copy = {}
            copies[orig] = copy
            for orig_key, orig_value in next, orig, nil do
                copy[deepcopy(orig_key, copies)] = deepcopy(orig_value, copies)
            end
            setmetatable(copy, deepcopy(getmetatable(orig), copies))
        end
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

重要的是,只提供一個引數給這個版本的 deepcopy 函式。否則,它會嘗試將第二個引數用作表格,這可能會造成意外的後果。

此外,由於這些函式具有遞迴性,因此使用它們複製非常深的表格可能會溢位堆疊。

非遞迴深層複製

可以從 [此 GitHub gist] 取得更靈活的(非遞迴)deepcopy 實作。它允許就如何複製特殊類型、元表和函式上值(包括合併)制定不同的規則。請參閱說明以了解用法。
RecentChanges · 喜好設定
編輯 · 歷史
最後編輯日期為 2022 年 12 月 6 日,上午 10:07 (GMT) (diff)