为什么将一个表赋值给另一个表会引起问题?
为什么在 Lua 中我们不能直观地复制表,像这样:
a = {
a = {},
b = {},
}
b = {}
b = a.b
我试图这样做时遇到了一些奇怪的错误。如果我使用以下的表克隆函数,它就可以正常工作,但我不明白为什么需要使用克隆函数或者这种方式为什么是最佳实践。
很难描述我尝试使用第一种方法遇到的错误,但基本上,如果我尝试在 a.b 部分的 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
然后使用以下方法就可以消除任何错误。
b = deepCopy(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 中的表的任何人。
那么,为什么将表存储到变量中不会复制表的内容?有几个原因。
深层复制是昂贵的。如果所有副本都是深层的,甚至不能执行简单的
return {1, 2, 3}而不执行复制。毫无意义的复制,因为没有其他变量可以访问该表(因为它是在现场创建的)。为什么浪费性能?将同样适用于将表作为参数传递给函数或任何其他数量的事情。仅深层复制会阻止有用的事情,例如在不同位置访问相同的表。如果每个表副本都是深的,那么您如何获得简单的模块表的本地副本?您无法让表“成员函数”返回对象内部的表,因此您可以使用该返回来操作该对象中的数据,因为该返回将不得不复制表。因此,只能通过直接成员函数修改表对象。
深度复制是一种有用的工具。但它不是默认值,因为它不应该是。大多数复制表的情况不需要它,而用户需要一种可以从多个位置访问表的方法。
也没有深复制的标准函数或机制。原因很简单:可以使用许多方法进行深度复制,从简单到复杂不等。例如,您的简单 deepCopy 函数会对存储它自己(递归地)的表发生错误:
me = { a = 4, other = {} }
me.other.me = me
这是 100% 的有效性,但是您的 deepCopy 函数将在其上发生故障。有一些方法可以实现 deepCopy,使其处理这种情况,但是它们是复杂且昂贵的。大多数用户不需要能够处理递归对象的 deepCopy。
如果 Lua 的标准库中有深层复制函数,那么它将处理每个这样的情况(因此是昂贵的),或者它将是一个较简单的函数,可以在任何角落情况(在表格中具有多个对同一表格的引用等)下出错。
因此,最好让使用深度复制的潜在用户坐下来,并确切地决定他们想处理哪些情况,哪些情况不需要。
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

我的建议是,只有在确实需要时才复制表格,并首选浅复制,除非确实需要深复制。事实上,当我需要复制表格时,我通常编写一个专门的复制函数,以便我不会复制更多的内容。