最近我写了一些Lua代码,如:
local a = {}
for i = 1, n do
local copy = a
-- alter the values in the copy
end
Run Code Online (Sandbox Code Playgroud)
显然,这不是我想要做的,因为变量持有对匿名表的引用而不是Lua中表本身的值.Lua中的编程清楚地阐述了这一点,但我忘了它.
所以问题是我应该写什么而不是copy = a获取值的副本a?
Dou*_*oub 43
表副本有许多潜在的定义.这取决于您是想要简单还是深度复制,是否要复制,共享或忽略元数据等.没有单一的实现可以满足每个人.
一种方法是简单地创建一个新表并复制所有键/值对:
function table.shallow_copy(t)
local t2 = {}
for k,v in pairs(t) do
t2[k] = v
end
return t2
end
copy = table.shallow_copy(a)
Run Code Online (Sandbox Code Playgroud)
请注意,您应该使用pairs而不是ipairs,因为ipairs只迭代表键的一个子集(即,以递增的顺序从一开始的连续正整数键).
Nor*_*sey 30
为了说明这一点,我的个人table.copy也关注metatables:
function table.copy(t)
local u = { }
for k, v in pairs(t) do u[k] = v end
return setmetatable(u, getmetatable(t))
end
Run Code Online (Sandbox Code Playgroud)
没有足够广泛认同的复制功能被称为"标准".
Tyl*_*ler 21
要玩一点可读代码高尔夫,这是一个处理标准棘手案例的简短版本:
我们可以用7行来做到这一点:
function copy(obj, seen)
if type(obj) ~= 'table' then return obj end
if seen and seen[obj] then return seen[obj] end
local s = seen or {}
local res = setmetatable({}, getmetatable(obj))
s[obj] = res
for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end
return res
end
Run Code Online (Sandbox Code Playgroud)
在这个要点中简要介绍了Lua深层复制操作.
另一个有用的参考是这个Lua-users wiki页面,其中包含一个如何避免__pairsmetamethod的示例.
小智 12
完整版的深层复制,处理所有3种情况:
一般版本:
local function deepcopy(o, seen)
seen = seen or {}
if o == nil then return nil end
if seen[o] then return seen[o] end
local no
if type(o) == 'table' then
no = {}
seen[o] = no
for k, v in next, o, nil do
no[deepcopy(k, seen)] = deepcopy(v, seen)
end
setmetatable(no, deepcopy(getmetatable(o), seen))
else -- number, string, boolean, etc
no = o
end
return no
end
Run Code Online (Sandbox Code Playgroud)
或表格版本:
function table.deepcopy(o, seen)
seen = seen or {}
if o == nil then return nil end
if seen[o] then return seen[o] end
local no = {}
seen[o] = no
setmetatable(no, deepcopy(getmetatable(o), seen))
for k, v in next, o, nil do
k = (type(k) == 'table') and k:deepcopy(seen) or k
v = (type(v) == 'table') and v:deepcopy(seen) or v
no[k] = v
end
return no
end
Run Code Online (Sandbox Code Playgroud)
基于lua-users.org/wiki/CopyTable和Alan Yates的功能.
小智 10
一个可选的深度,图形通用的递归版本:
function table.copy(t, deep, seen)
seen = seen or {}
if t == nil then return nil end
if seen[t] then return seen[t] end
local nt = {}
for k, v in pairs(t) do
if deep and type(v) == 'table' then
nt[k] = table.copy(v, deep, seen)
else
nt[k] = v
end
end
setmetatable(nt, table.copy(getmetatable(t), deep, seen))
seen[t] = nt
return nt
end
Run Code Online (Sandbox Code Playgroud)
也许metatable副本也应该是可选的?
这是我实际做的:
for j,x in ipairs(a) do copy[j] = x end
Run Code Online (Sandbox Code Playgroud)
作为DOUB提到,如果表项不严格单调递增的,它应该是pairs没有ipairs.
我还发现了一个deepcopy更强大的功能:
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
Run Code Online (Sandbox Code Playgroud)
它通过递归调用自身来处理表和元表(这是它自己的奖励).其中一个聪明的部分是你可以传递任何值(无论是否是表),它将被正确复制.但是,成本是它可能会溢出堆栈.因此,可能需要更强大(非递归)的功能.
但是对于想要将数组复制到另一个变量的非常简单的情况来说,这太过分了.