Lua 为什么将一个表作为值分配给另一个表会导致问题?
为什么我们不能像这样在Lua中直观地复制表:Lua 为什么将一个表作为值分配给另一个表会导致问题?,lua,Lua,为什么我们不能像这样在Lua中直观地复制表: a = { a = {}, b = {}, } b = {} b = a.b 我遇到了一些奇怪的虫子在做这件事。如果我像下面这样使用表克隆函数,它会工作得很好,我只是不明白为什么首先需要使用克隆函数/最佳实践 很难描述我在尝试使用第一种方法时遇到的错误,但基本上,如果我尝试在b=a.b的a.b部分中添加额外的键值,那么额外的键值并不总是成为我设置的值 function deepCopy(object) local lookup_
a = {
a = {},
b = {},
}
b = {}
b = a.b
我遇到了一些奇怪的虫子在做这件事。如果我像下面这样使用表克隆函数,它会工作得很好,我只是不明白为什么首先需要使用克隆函数/最佳实践
很难描述我在尝试使用第一种方法时遇到的错误,但基本上,如果我尝试在b=a.b
的a.b
部分中添加额外的键值,那么额外的键值并不总是成为我设置的值
function deepCopy(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
然后执行以下操作将删除所有bug
b = deepCopy(a.b)
- 变量包含引用,而不是整个表
- 复制一个引用比复制整个表要高效得多
- 函数调用有效地将参数分配给该函数的参数,因此,如果分配是完整的,则不可能编写修改表的函数
- 通常,当我们将一个表分配给某个对象时,我们要么(a)不打算修改该表,要么(b)明确打算使用至少一个变量来修改基础表。请参见前面关于函数的一点。这意味着默认情况下进行完整复制将是一种资源浪费
- 变量包含引用,而不是整个表
- 复制一个引用比复制整个表要高效得多
- 函数调用有效地将参数分配给该函数的参数,因此,如果分配是完整的,则不可能编写修改表的函数
- 通常,当我们将一个表分配给某个对象时,我们要么(a)不打算修改该表,要么(b)明确打算使用至少一个变量来修改基础表。请参见前面关于函数的一点。这意味着默认情况下进行完整复制将是一种资源浪费
我的建议是只在您真正需要的时候复制表,如果您确实需要深度复制,则更喜欢浅层复制。事实上,当我需要复制表时,我通常会编写一个专门的复制函数,这样我就不会复制任何超出我需要的内容。在Lua中,表是一个值,每个不同的表都有一个不同的值。表的值用于标识其内容,但表的内容在概念上不是表的值。也就是说,要访问表的内容,需要表的值,但表的值与其内容不同 表的值可以存储在任何变量中。同样,该值用于标识该表并访问该表的内容,但这与逻辑上作为该表内容的值不同 考虑以下几点:
tbl1 = { 1, 2, 3 }
tbl2 = tbl1
tbl3 = { 1, 2, 3 }
tbl1
和tbl2
的值相同;这意味着它们都引用同一个表,因此您可以通过任一变量访问该表的内容。所以tbl1[2]
和tbl2[2]
不要简单地返回2;它们都访问同一个表
tbl3
与tbl1
不同。它们可能有逻辑上相同的内容,但就Lua而言,它们是不同的表。操作tbl3
中存储的表的内容不会影响查看tbl1
或tbl2
中存储的表的任何人
那么,为什么将表存储到变量中不会复制表的内容呢?有几个原因
返回{1,2,3}
。一个无意义的副本,因为没有其他变量可以与该表对话(因为它是在原位创建的)。为什么要浪费性能?将表作为参数传递给函数或任何其他对象也是如此deepCopy
函数在一个表上中断,该表存储(递归)自身:
这是100%有效的,您的deepCopy
功能将在其上中断。有一些方法可以实现deepCopy
,这样它就可以处理这个问题,但它们既复杂又昂贵。大多数用户不需要能够处理递归对象的deepCopy
如果Lua的标准库有一个深度复制功能,那么它要么可以处理每一个这样的情况(因此成本很高),要么可以是一个更简单的库,可以处理任意数量的角情况(在一个表中有多个对同一个表的引用,等等)
因此,最好让深度副本的任何潜在用户坐下来,确切地决定他们想要处理哪些情况,哪些情况不需要处理。在Lua中,表是一个值,每个不同的表都有一个不同的值。表的值用于标识
me = { a = 4, other = {} }
me.other.me = me