前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Sweet Snippet 系列之 Clone Lua Table

Sweet Snippet 系列之 Clone Lua Table

作者头像
用户2615200
发布2018-08-02 16:48:02
3810
发布2018-08-02 16:48:02
举报

引子

参加工作好多年了,却一直对程序中的clone(拷贝)语义比较陌生,印象中很多开发书籍对此都有很大篇幅的讨论,但自己平日里用到的情况却很少. 细想一下原因,可能还是由于拷贝的定义不明引起的:深拷贝浅拷贝几乎是开发人员的常识,概念上似乎很简单,但是真正联系到实际项目,那就需要仔细思忖了. 就拿Lua中table举例,我们现在想要执行一次深拷贝操作,简单来想似乎写个递归就可以了,代码大概是这个样子:

代码语言:javascript
复制
function clone(tbl)
  if type(tbl) ~= "table" then 
      return tbl 
  end
  local clone_tbl = {}
  for k, v in pairs(tbl) do
      clone_tbl[clone(k)] = clone(v)
  end
  return clone_tbl
end

但是这个实现有几个问题: 1. 没有处理metatable(元表) 2. 不能处理recursive table(table中存在递归的引用,最简单的情况便是table中存在对自身的引用) 3. table可能定义了__pairs 元方法,代码直接使用pairs遍历table执行拷贝可能存在问题

对于recursive table的问题我们可以通过缓存记录来解决,但是对于metatable相关的两个问题却没有简单答案了,网上很多同学提供的方案都是使用setmetatable(clone_tbl, getmetatable(tbl))的方式来进行设置,但实际上,哪怕你确实需要保持元表关系,也仍然需要根据实际的项目情况来决定是否还需要深拷贝元表(setmetatable(clone_tbl, clone(getmetatable(tbl))))

代码

这里简单列个参考实现(细节大部分还是根据自己的项目需求所定)

代码语言:javascript
复制
local function clone_table_shallow(tbl)
    if type(tbl) ~= "table" then
        return tbl
    else
        local clone_table = {}
        for k, v in pairs(tbl) do
            clone_table[k] = v
        end
        return clone_table
    end
end

local function clone_table_recur(tbl, lookup_table)
    if type(tbl) ~= "table" then
        return tbl
    elseif lookup_table[tbl] then
        return lookup_table[tbl]
    end

    local new_table = {}
    lookup_table[tbl] = new_table
    for key, value in pairs(tbl) do
        new_table[clone_table_recur(key, lookup_table)] = clone_table_recur(value, lookup_table)
    end
    return new_table
end

local function clone_table_deep(tbl)
    local lookup_table = {}
    return clone_table_recur(tbl, lookup_table)
end

-- NOTE : 
-- 1. do not handle "metatable" now
-- 2. only support "table" clone
-- 3. it will influence by the "__pairs" metamethod
function clone(tbl, shallow_clone)
    if shallow_clone then
        return clone_table_shallow(tbl)
    else
        return clone_table_deep(tbl)
    end
end

更多

关于这个话题的更多讨论可以看这里这里,参考的gist代码可以在这里这里找到

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年03月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引子
  • 代码
  • 更多
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档