Variables 如何在Lua中获取表的实际副本?
因此,以下变量均指同一个表:Variables 如何在Lua中获取表的实际副本?,variables,lua,Variables,Lua,因此,以下变量均指同一个表: 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使真正通过值而不仅仅是引用复制变量变得如此困难 为什么Lua使真正通过值而不仅仅是引用复制变量变得如此困难 因为“复制”一张表的意义很大程度上取决于该表中的内容
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使真正通过值而不仅仅是引用复制变量变得如此困难
为什么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
此表现在有两个引用同一表的字段。如果您想获得该表的真实副本,那么副本需要认识到两个字段相互引用,以便在复制第一个字段时,第二个字段可以引用新副本,而不是再次复制它
我甚至还没有进入元表和你能接触到的体操。这也不包括对基本上不可复制的事物的讨论,比如来自基于C的API的userdata对象。如果我将io.open
的结果存储在表中,则没有复制该文件句柄的机制。那么,您的复制例程应该做什么呢
Lua没有默认的表复制API,以确保您自己能够花时间了解复制算法需要有多复杂。只需将值分配给新变量,就可以复制数字或字符串。另一方面,桌子需要更多的工作 要在lua中复制表,需要定义一个复制函数。 两种常见的复制函数类型是浅复制和深复制 浅拷贝: 这是一个简单、幼稚的实现。它只复制顶级值及其直接子级;不需要处理更深层次的子级、元表或特殊类型,如用户数据或协同路由。它也容易受到_配对元方法的影响 深度复制: 深度副本复制所有级别(或级别的特定子集)。 下面是一个简单的递归实现,它额外处理元表并避免_对元方法
正如Nicol Bolas所说,复制表有很多陷阱。 在另一个SO问题中,给出了以下示例,该示例确实涵盖了一些令人关注的案例,例如:
- 表作为键
- 保持元表
- 递归表
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)}
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}
y = {table.unpack(x)}