废话:好久没在这里写博客了。。。主要原因是我买了个域名hanxi.info并在github上搭建了个人博客。。。

  lua中默认是没有c中的const常量的,在csdn上找到了一个使用setmetatable。参考http://blog.csdn.net/xiaodan007/article/details/6668015。主要原理就是重载__index方法(相当于get方法)和__newindex方法(相当于set方法)。但是他实现的是不支持表中有表的情况的。

下面是我修改后的代码:

 function newConst( const_table )    --生成常量表功能
     function Const( const_table )
         local mt =
         {
             __index = function (t,k)
 6                 if type(const_table[k])=="table" then
 7                     const_table[k] = newConst(const_table[k])
                 end
                 return const_table[k]
             end,
             __newindex = function (t,k,v)
                 print("*can't update " .. tostring(const_table) .."[" .. tostring(k) .."] = " .. tostring(v))
             end
         }
         return mt
     end

     local t = {}
     setmetatable(t, Const(const_table))
     return t
 end

 quan = {a = {[]={}}}
 quan.b = quan
 t = newConst(quan)
 --t.b = 4
 print(type(t))
 print(quan.b)

 for k,v in pairs(quan) do
 print(k,v)
 end

  我也就是添加了6,7,8三行代码(刚开始想了半天以为递归了,结果思索了下,不是递归,只是函数的实现形式,调用newConst的次数就是读取表的深度,有环的表也不会出现问题的)。__index函数(看参数可以知道取元素t[k])拿到表的元素,如果元素是表则先将表常量化。__newindex函数(看参数可以知道写元素t[k]=v)是给元素赋值,这里不让它实现赋值操作,直接打印错误提示。

  为什么要实现这个常量功能,因为现在的手游项目中使用了lua表存放数值策划表,往往程序写代码时会直接去读取静态数据表,万一不小心把表元素赋值了,那就是把静态数据改了,会导致游戏数据错误的。实现了这个lua常量就不会出现静态数据表被修改了。

  但是如果需要复制一份静态数据,然后作为临时数据在游戏逻辑中处理(一个同事就这么用过。。。),把静态数据经过了常量处理就再也不能被修改了,不常量化也不行,中途被修改了就再也还原不了静态数据了。因此就需要实现lua表的深拷贝功能了(默然的表与表之间赋值只是简单的别名而已)。先说下思路吧,实现的效果是:

local B = deepcopy(A,n)

  把A拷贝给B,n为拷贝深度。如果n为nil时那就是说要拷贝到底了,这又出现了中有环的问题了,不考虑环的问题可以很简单的递归实现,递归结束标识就是判断n的值。代码就先不写了,晚了洗洗睡吧。下次有时间会贴代码的。。。

  网上关于深拷贝表的资料很少。总共在下面几个网站上找到了答案。

http://blog.sina.com.cn/s/blog_49bdd36d0100fdc1.html(集合了带环的table和不带环的table的解决方案)

http://www.coronafaqs.com/how-do-i-copy-a-complex-table-in-lua/(就是上面那个带坏的table的解决方案)

http://lua-users.org/wiki/CopyTable(不带环的table的解决方案,还有一个浅拷贝实现)

https://gist.github.com/Deco/3985043 (牛逼的解决方案,非递归实现,能够处理带环的table)

  先给上递归式的代码吧。

 function table.deepcopy(object)
     local lookup_table = {}
     local function _copy(object)
         if type(object) ~= "table" then
             return object
         elseif lookup_table[object] then
             return lookup_table[object]
         end
         local new_table = {}
         lookup_table[object] = new_table
         for index, value in pairs(object) do
             new_table[_copy(index)] = _copy(value)
         end
         return setmetatable(new_table, getmetatable(object))
     end
     return _copy(object)
 end

为啥带环的table用这个函数不会无限递归呢?关键之处在于lookup_table,它记录了所有遍历过的table的副本(新的深拷贝的table),如果出现遍历过的直接返回那个副本。第12行为何有两个_copy,这里用的很巧妙,举个例子吧。

t = {

a = 1,

b = 2,

c = {

x = 1,

y = 2,

z = 3,

}

}

t[t.c] = t

t2 = table.deepcopy(t)

print(t2[t2.c])

如果index没有经过_copy处理,则打印出来的则是nil。为何经过_copy处理一定会是t2.c==t2呢?这也就是第6行判断的效果了,它返回的index就是t2.c(因为t2.c要么就是从第7行返回的,要没是新生成的副本,下次拷贝时还是取得同一个副本)。

接下来看第14行,这行不是我想要的,我的目的是拷贝出一份临时表,这分临时表要去除常量的特性,所以我修改如下

return setmetatable(new_table)

这样也就不保留常量特性了。

lua中使用局部函数的好处是很多的。look_up就用到了这个好处,如果lua不支持局部函数,那就只能将look_up表当做参数传递进去了。我之前实现了不支持环的版本,如下:

 function table.deepcopy(t, n)
     local newT = {}
     if n == nil then    -- 默认为浅拷贝。。。
         n =
     end
     for i,v in pairs(t) do
          and type(v) == "table" then
             )
             newT[i] = T
         else
             local x = v
             newT[i] = x
         end
     end
     return newT
 end

非递归版本太牛逼了,不做介绍了自己想看源码的去看吧

lua中常量的实现及表的深拷贝实现的更多相关文章

  1. Lua中metatable和__index的联系

    Lua中metatable和__index的联系 可以参考 http://blog.csdn.net/xenyinzen/article/details/3536708 来源 http://blog. ...

  2. Lua中的weak表——weak table

    弱表(weak table)是一个很有意思的东西,像C++/Java等语言是没有的.弱表的定义是:A weak table is a table whose elements are weak ref ...

  3. Lua中的weak表——weak table(转)

    弱表(weak table)是一个很有意思的东西,像C++/Java等语言是没有的.弱表的定义是:A weak table is a table whose elements are weak ref ...

  4. [译] Closures in Lua - Lua中的闭包

    原文:(PDF) . 摘要 一等(first-class)函数是一种非常强大的语言结构,并且是函数式语言的基础特性.少数过程式语言由于其基于栈的实现,也支持一等函数.本文讨论了Lua 5.x用于实现一 ...

  5. lua中基类和“继承机制”

    基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lu ...

  6. lua中的string类型

    在lua中用union TString来表示字符串类型 lobject.h: 其中结构体tsv中 reserved字段表示字符串是不是保留关键字,hash是其哈希值,len是其长度.我们在TStrin ...

  7. lua中的table、stack和registery

    ok,前面准备给一个dll写wrapper,写了篇日志,看似写的比较明白了,但是其实有很多米有弄明白的.比如PIL中使用的element,key,tname,field这些,还是比较容易混淆的.今天正 ...

  8. lua 中的面向对象

    lua 是一种脚步语言,语言本身并不具备面向对象的特性. 但是我们依然可以利用语言的特性,模拟出面向对象的特性. 面向对象的特性通常会具备:封装,继承,多态的特性,如何在lua中实现这些特性,最主要的 ...

  9. lua中得栈

    如果你看了LUA的文档,那么就应该很清楚LUA与C交互数据时都是用到LUA中所谓的stack.那么当我调用lua_open函数之后栈是什么样的呢?空的(luaopen_base等会往栈上加进一些东西) ...

随机推荐

  1. zabbix身份验证流程解析&绕过身份验证的方法

    由于实验室产品的监控模块的需求,需要绕过zabbix的验证模块,实现从二级平台到zabbix的无缝接入. 测试发现,zabbix的身份验证并不是想象的那么简单,为了实现功能,遂进行源码分析. zabb ...

  2. ahjesus web动态icon

    刚刚逛插件无意间发现的,记录下,里面有demo可以直接run了看效果 http://nicolasbize.com/faviconx/ http://www.miaofree.com/

  3. 聊聊Azure的安全性

    本来没打算写这篇博文,毕竟感觉太理论化,不像做技术的人应该写的东西,但是作为一名售前,发现很多不了解Azure的客户,上来的第一个问题竟然就是Azure如何保证客户数据的安全性,我清楚记得我第一次被问 ...

  4. androidService总结

    2.服务 2-1:启动服务 2-1-1:创建服务 extends Service 2-1-2:注册 <service android:name="com.firefly.style_s ...

  5. ecshop 全站内页 显示最新文章

    一.打开根目录下index.php,找到代码 $smarty->assign('new_articles',    index_get_new_articles());   // 最新文章 进行 ...

  6. C++中的静态绑定和动态绑定

    C++在面向对象编程中,存在着静态绑定和动态绑定的定义,本节即是主要讲述这两点区分.我是在一个类的继承体系中分析的,因此下面所说的对象一般就是指一个类的实例.首先我们需要明确几个名词定义: 静态类型: ...

  7. 20150612_Andriod contextual action mode 菜单

    参考地址:http://www.xuebuyuan.com/1114028.html              http://www.cnblogs.com/mengdd/p/3564782.html ...

  8. Collaborative&#160;filtering

        Collaborative filtering, 即协同过滤,是一种新颖的技术.最早于1989年就提出来了,直到21世纪才得到产业性的应用.应用上的代表在国外有Amazon.com,Last. ...

  9. HTML &lt;input&gt; 标签的 maxlength 属性

    前端的表单,需要进行验证. 结合JS表单验证框架,写了很多前端验证的代码. 其中,有这么一个需求:用户最多只能输入10个字符. 按照惯性,肯定是会去写JS表单验证了. 实际上,根本没有必要. HTML ...

  10. Android:AlertDialog对话框

    1.简单的ALertDialog: Dialog alertDialog = new AlertDialog.Builder(this) .setTitle("标题") .setM ...