如何在Lua中实际复制变量?

时间:2018-12-31 18:19:03

标签: 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很难真正通过值而不是仅通过引用来复制变量?

2 个答案:

答案 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中复制表,您需要定义复制功能。 两种常见的复制功能类型是浅复制和深复制。

Lua-users: CopyTable

浅拷贝

  

这是一个简单,幼稚的实现。它仅复制顶级值及其直接子级;无法处理更深的子级,元表或特殊类型,例如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)}