因此,以下变量均引用同一张表:
x = {1,2,3}
y=x
z=y
table.remove(z,3)
因此以下代码将输出1,2
for k,v in pairs(x) do
print(v)
end
互联网只是指Lua始终通过引用而不是值使用变量的能力。
但是有时候我想操纵一个变量的副本,而不是原始变量。怎么做?为什么Lua很难真正通过值而不是仅通过引用来复制变量?
答案 0 :(得分:5)
为什么Lua很难真正通过值而不是仅通过引用来复制变量?
因为“复制”表的含义在很大程度上取决于该表中的。
首先,一些术语。您不是在引用“变量”;您将获得对表的引用。 “变量”只是内容的持有人,例如数字,字符串或对表的引用。
因此,当您说“真正复制变量”时,实际上是指“复制表”。而且...这并不容易。
考虑此表:
local tbl = {x = 5, y = {20}}
如果要复制该表,是否要让新表的y
字段具有旧表存储的表的副本?还是您希望该表格本身就是原始表格的副本?
两个答案都不对。您想要哪一个完全取决于您想做什么。但是您不能盲目地制作表的递归副本,因为:
local tbl = {x = 5, y = {20}}
tbl._tbl = tbl
此表现在存储对自身的引用 。尝试对该表进行盲式递归副本将导致无限递归。您将必须检测到该表引用了自己,因此新表存储了对新表的引用。而且变得更加复杂:
local tbl = {x = 5, y = {20}}
tbl.z = tbl.y
此表现在有两个引用同一表的字段。如果要获得该表的真实副本,则该副本需要意识到两个字段相互引用,以便在复制第一个字段时,可以让第二个字段引用新副本,而不必再次复制它。
而且我什至还没有涉足 metatables 和您可以跟上的体操运动。这也不包括对根本不可复制的内容的讨论,例如,基于C的API中的userdata对象。如果我将io.open
的结果存储在表中,则没有用于复制该文件句柄的机制。那么您的复制例程应该做什么?
Lua没有默认的表复制API,以确保您自己花时间弄清楚复制算法的复杂程度。
答案 1 :(得分:2)
只需将值分配给新变量即可复制数字或字符串。另一方面,桌子将需要更多的工作。
要在lua中复制表,您需要定义复制功能。 两种常见的复制功能类型是浅复制和深复制。
浅拷贝:
这是一个简单,幼稚的实现。它仅复制顶级值及其直接子级;无法处理更深的子级,元表或特殊类型,例如userdata或协程。它也容易受到__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
正如Nicol Bolas所说,复制表格有很多陷阱。 在另一个SO问题how-do-you-copy-a-lua-table-by-value中,给出了以下示例,该示例确实涵盖了一些令人关注的情况,例如;
泰勒的例子:
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
每个功能都有不同的用例,如果您使用的是x = {1,2,3}
之类的浅表,则可以执行以下操作:
x = {1,2,3}
y = {table.unpack(x)}