深度复制函数变量给出了意想不到的结果
deepcopying function variable gives unexpected results
我有一个使用以下函数创建的对象
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
函数变量完全错误。它不再是传递给对象的函数并产生意想不到的结果
有很多地方可能会出错,而且没有足够的信息来确定。但是,我看到有些地方可能与您的副本有问题,尤其是看起来有问题的地方。
您的 deepcopy 函数将复制对象的元table:
-- snip...
setmetatable(copy, deepcopy(getmetatable(t)))
-- ...
但是,相同类型的对象共享相同的元是一种相当普遍的做法table,而且,您的代码似乎是这样做的(尽管没有看到 Objectmt 是如何定义的,它是'清楚)。例如,其他代码可以通过执行以下操作来确定某物是否为对象:
function isObject(obj)
return getmetatable(obj)==Objectmt
end
您的副本将失败,因为元table 不再相同(即使它具有相同的内容)。
这可以通过使用不同版本的 deepcopy(或修改现有版本)重用元数据来解决table:
-- snip...
setmetatable(copy, getmetatable(t))
-- ...
如果这不是问题,那么还需要考虑一些其他事项:
- 您的深度复制功能不会复制 table 键。在某些情况下,复制密钥可能很重要,但对于您显示的任何代码而言,情况似乎并非如此。
- 你的deepcopy函数不会复制函数。如果您使用具有 mutable upvalues 的函数,这可能很重要。同样,您显示的任何代码都不是这种情况。
- 除了 metatable 之外,可能还有其他 table 应该通过引用而非值进行复制。要知道哪个合适,你必须了解它们的使用方式。
- 可能存在当前通过引用复制的用户数据或其他不太常见的类型(例如协程),需要通过值进行复制。有些东西可能无法按值复制。
- 您正在复制的数据中可能存在根本不应该复制的内容,例如唯一标识符。
- 问题可能根本不在于副本。
我有一个使用以下函数创建的对象
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
函数变量完全错误。它不再是传递给对象的函数并产生意想不到的结果
有很多地方可能会出错,而且没有足够的信息来确定。但是,我看到有些地方可能与您的副本有问题,尤其是看起来有问题的地方。
您的 deepcopy 函数将复制对象的元table:
-- snip...
setmetatable(copy, deepcopy(getmetatable(t)))
-- ...
但是,相同类型的对象共享相同的元是一种相当普遍的做法table,而且,您的代码似乎是这样做的(尽管没有看到 Objectmt 是如何定义的,它是'清楚)。例如,其他代码可以通过执行以下操作来确定某物是否为对象:
function isObject(obj)
return getmetatable(obj)==Objectmt
end
您的副本将失败,因为元table 不再相同(即使它具有相同的内容)。
这可以通过使用不同版本的 deepcopy(或修改现有版本)重用元数据来解决table:
-- snip...
setmetatable(copy, getmetatable(t))
-- ...
如果这不是问题,那么还需要考虑一些其他事项:
- 您的深度复制功能不会复制 table 键。在某些情况下,复制密钥可能很重要,但对于您显示的任何代码而言,情况似乎并非如此。
- 你的deepcopy函数不会复制函数。如果您使用具有 mutable upvalues 的函数,这可能很重要。同样,您显示的任何代码都不是这种情况。
- 除了 metatable 之外,可能还有其他 table 应该通过引用而非值进行复制。要知道哪个合适,你必须了解它们的使用方式。
- 可能存在当前通过引用复制的用户数据或其他不太常见的类型(例如协程),需要通过值进行复制。有些东西可能无法按值复制。
- 您正在复制的数据中可能存在根本不应该复制的内容,例如唯一标识符。
- 问题可能根本不在于副本。