原因
由于lua的弱类型动态语言的特质,克隆table的行为在lua中不说无处不在,那也是非常常见。
一般克隆table原因无外乎:
- 通过修改旧table的部分数据创建新table,然后又不想由于修改新table而导致旧table被修改。从而保持函数的纯函数性。
方法
那怎么做到呢?有如下方法:
- 直接克隆。这种方式创建出来的table是全新的实例,怎么修改也不会影响到原table,缺点是在table较大的时候创建耗时较久,也会占用更多内存
function createNewTable(tb)
local newTb = clone(tb)
newTb.id = 2
return newTb
end
local tbA = {a = 1}
local tbB = createNewTable(tbA)
print(tbB.a) -- 1
print(tbB.b) -- 2
tbB.a = 3
tbB.b = 4
print(tbB.a) -- 3
print(tbB.b) -- 4
tbB.a = nil
tbB.b = nil
print(tbB.a) -- nil
print(tbB.b) -- nil
- 通过元表将新修改的数据存储到新的table中。优点是创建速度快,占用内存少,修改的数据也会存储在新的table中,不会影响到原table。缺点是无法将原table中的变量赋值为空,且新的table无法用pairs和ipairs遍历到。
function createNewTable(tb)
local newTb = setmetatable({}, {__index = tb})
newTb.b = 2
return newTb
end
local tbA = {a = 1}
local tbB = createNewTable(tbA)
print(tbB.a) -- 1
print(tbB.b) -- 2
tbB.a = 3
tbB.b = 4
print(tbB.a) -- 3
print(tbB.b) -- 4
tbB.a = nil
tbB.b = nil
print(tbB.a) -- 1
print(tbB.b) -- nil
-- 只会输出b=1, 遍历不到tbA中的数据
for k, v in pairs(tbB) do
print(k, v)
end
克隆和元表实现的优缺点
克隆 | 元表 | |
优点 | 创建出新table,可遍历 | 创建迅速,占用内存少 |
缺点 | 当被克隆的table较大的时候,耗时较久,并且占用内存较多 | 不可以设置原table已有的值为nil,不可使用pairs和ipairs遍历 |
预告
有没有一种方式创建出来的新table,可以兼顾克隆和元表两者的优点,既创建速度快,占用内存少,又可以肆意修改,并且完全不影响到原来的table还能支持遍历呢?
下篇见。