deepcopying函数变量给出了意想不到的结果

时间:2015-03-22 01:47:31

标签: function lua copy deep-copy luajit

我有一个使用以下函数创建的对象

local function newObject(functionVariable)
    ...
    functionVariable = functionVariable or nop
    ...
    return setmetatable({
        ...
        functionVariable         = functionVariable,
        ...
    }, Objectmt)
end

当我使用此

深度查看此对象时
local function deepcopy(t)
    if t == nil then return nil end

    if type(t) == 'table' then
            local copy = {}

            for k, v in pairs(t) do
                    copy[k] = deepcopy(v)
            end
            setmetatable(copy, deepcopy(getmetatable(t)))
            return copy
    else -- number, string, boolean, etc
            return t
    end
end

并使用此

加载对象
for k, v in pairs(state.objectsTable) do objectsTable[k] = v end

函数变量完全错误。它不再是传递给对象的函数,而是产生了意想不到的结果

1 个答案:

答案 0 :(得分:2)

有很多事情可能出错,而且没有足够的信息可以说肯定。但是,有些事情我可以看到你的副本可能有问题,尤其是一个看起来有问题的东西。

您的deepcopy函数将复制对象的元表:

-- snip...
setmetatable(copy, deepcopy(getmetatable(t)))
-- ...

但是,相同类型的对象共享相同的元表是一种相当普遍的做法,而且,您的代码似乎也这样做(虽然没有看到如何定义Objectmt,但目前尚不清楚)。例如,其他代码可以通过执行以下操作来确定某些东西是否为对象:

function isObject(obj)
  return getmetatable(obj)==Objectmt
end

这将使您的副本失败,因为metatable不再相同(即使它具有相同的内容)。

这可以通过使用不同版本的deepcopy(或修改现有版本)来重用metatable来解决:

-- snip...
setmetatable(copy, getmetatable(t))
-- ...

如果这不是问题,那么还有其他一些事情需要考虑:

  • 您的deepcopy功能不会复制表键。在某些情况下,复制密钥可能很重要,但对于您显示的任何代码,情况似乎并非如此。
  • 您的deepcopy功能不会复制功能。如果您使用具有可变upvalues的函数,这可能很重要。同样,您所显示的任何代码都不是这种情况。
  • 除了metatable之外还有其他表应该通过引用而不是值来复制。要知道哪个是合适的,你必须了解它们的使用方式。
  • 可能存在当前通过引用复制的userdata或其他不太常见的类型(例如协同程序),需要按值复制。有些东西可能无法按值复制。
  • 您正在复制的数据中可能存在根本不应复制的内容,例如,唯一标识符。
  • 问题可能与版本无关。