0%

Lua Deep Copy

浅拷贝

Lua语言基础数据类型的拷贝采用值传递的方式;table类型变量的拷贝采用弱引用的方式,像C++语言中的引用传参数。

1
2
3
4
5
local a = {12}
local b = a

print(a)        -->table: 0x82b080
print(b)        -->table: 0x82b080

可以看到a,b 指向了同一个内存地址,即指向了同一个元素。

深度拷贝

这种弱引用的赋值方式有利有弊,那么如果我们想对一个变量进行深度拷贝(deep copy)呢,就需要自己手动实现:

方法1

1
2
3
4
5
6
7
8
9
10
11
12
function copy1(obj)
   if type(obj) ~= 'table' then
      return obj
   end
 
   local res = {}
   for k, v in pairs(obj) do
      res[copy1(k)] = copy1(v)
   end
 
   return res
end

这种方法将深度拷贝的思想表现出来了,采用递归的方式逐层拷贝数据类型。普通元素直接赋值,table类型元素拆开后每个元素分别处理。
但这个算法有两种情况没考虑到:

  1. 元表的继承
  2. 当元素的table引用存在嵌套

方法2

继承元表

1
2
3
4
5
6
7
8
9
10
11
12
13
function copy2(obj)
    if type(obj) ~= 'table' then
        return obj
    end
 
    local res = setmetatable({}, getmetatable(obj))     -- (新加)继承元表
 
    for k, v in pairs(obj) do
        res[copy2(k)] = copy2(v)
    end
 
    return res
end

方法3

处理引用嵌套的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function copy3(obj, seen)
    -- Handle non-tables and previously-seen tables.
 
    if type(obj) ~= 'table' then
        return obj
    end
 
    if seen and seen[obj] then
        return seen[obj]
    end
 
    -- New table; mark it as seen an copy recursively.
    local s = seen or {}
    local res = setmetatable({}, getmetatable(obj))
    s[obj] = res
 
    for k, v in pairs(obj) do
        res[copy3(k, s)] = copy3(v, s)
    end
 
    return res
end
-- 其中seen为table,与其相关的代码负责处理递归引用的情况。

以上代码引用自:How to deep copy Lua values
感谢作者!