复制表 |
|
通用的 table.copy
函数不能保证适合所有用例,因为有许多不同的方面必须针对特定情况进行选择。例如:元表应该共享还是复制?我们应该检查用户数据是否有 __copy
元方法?这些问题(以及许多其他问题)必须由开发人员提出并回答。
一些 Lua “扩展标准库”,如 Penlight 和 stdlib 提供了现成的复制函数以方便使用。在实现自己的函数之前,请检查它们是否适合您的用例。
以下函数提供了一个基础来进行工作
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
函数提供一个参数。否则,它将尝试使用第二个参数作为表,这可能会产生意想不到的后果。
此外,由于这些函数是递归的,因此使用它们来复制非常深的表可能会导致堆栈溢出。