如果转载,请注明博文来源:http://www.cnblogs.com/vanishfan/p/6909153.html  望各位支持!

项目中部分只读表易被人误改写,故决定在非线上环境里对这些表附加只读属性,方便在出现误改写的时候抛出lua错误,最终版代码如下:

 --[[------------------------------------------------------------------------------
-** 设置table只读 出现改写会抛出lua error
-- 用法 local cfg_proxy = read_only(cfg) retur cfg_proxy
-- 增加了防重置设置read_only的机制
-- lua5.3支持 1)table库支持调用元方法,所以table.remove table.insert 也会抛出错误,
-- 2)不用定义__ipairs 5.3 ipairs迭代器支持访问元方法__index,pairs迭代器next不支持故需要元方法__pairs
-- 低版本lua此函数不能完全按照预期工作
*]]
function read_only(inputTable)
local travelled_tables = {}
local function __read_only(tbl)
if not travelled_tables[tbl] then
local tbl_mt = getmetatable(tbl)
if not tbl_mt then
tbl_mt = {}
setmetatable(tbl, tbl_mt)
end local proxy = tbl_mt.__read_only_proxy
if not proxy then
proxy = {}
tbl_mt.__read_only_proxy = proxy
local proxy_mt = {
__index = tbl,
__newindex = function (t, k, v) error("error write to a read-only table with key = " .. tostring(k)) end,
__pairs = function (t) return pairs(tbl) end,
-- __ipairs = function (t) return ipairs(tbl) end, 5.3版本不需要此方法
__len = function (t) return #tbl end,
__read_only_proxy = proxy
}
setmetatable(proxy, proxy_mt)
end
travelled_tables[tbl] = proxy
for k, v in pairs(tbl) do
if type(v) == "table" then
tbl[k] = __read_only(v)
end
end
end
return travelled_tables[tbl]
end
return __read_only(inputTable)
end

测试代码如下:

 local t0 = {k = }
local t2 = {
fdsf = {}
}
local t1 = {
a = {, },
b = {,ddss = , t2 = t2},
d = ,
e = "string",
}
t1.c=t1 local t3 = read_only(t1) print(t3.d, t3.c.e, t3.c.c.b.t2.fdsf)
function q1() t3.d = end
function q2() t3.c.d = end
function q3() t3.c.c.b.t2.fdsf = end
function q4() table.remove(t3.a) end
function q5() t3.b[ddss] = nil end
function q6() t3[f] = end
function q7() table.insert(t3.a, ) end print(pcall(q1))
print(pcall(q2))
print(pcall(q3))
print(pcall(q4))
print(pcall(q5))
print(pcall(q6))
print(pcall(q7))
print(t3.a[])
for k,v in pairs(t3) do
print("===pairs t3:",k,v)
end
for k,v in pairs(t3.a) do
print("===pairs t3.a:",k,v)
end
for k,v in ipairs(t3) do
print("===ipairs t3:",k,v)
end
for k,v in ipairs(t3.a) do
print("===ipair t3.a",k,v)
end
print("len t3:",#t3)
print("len t3.a:", #t3.a) local t4 = read_only(t2) local t5 = read_only(t0)
local t6 = read_only(t0) print(t3.b.t2, read_only(t2))
print(t5, t6, t0)

测试环境https://www.lua.org/cgi-bin/demo  lua5.3.4:

    string    table: 0x20d4ba0
false input:: error write to a read-only table with key = d
false input:: error write to a read-only table with key = d
false input:: error write to a read-only table with key = fdsf
false input:: error write to a read-only table with key =
false input:: error write to a read-only table with key = nil
false input:: error write to a read-only table with key = nil
false input:: error write to a read-only table with key = ===pairs t3: e string
===pairs t3: b table: 0x20ccd60
===pairs t3: a table: 0x20d4e70
===pairs t3: d
===pairs t3: c table: 0x20ca700
===pairs t3.a:
===pairs t3.a:
===ipair t3.a
===ipair t3.a
len t3:
len t3.a:
table: 0x20d4870 table: 0x20d4870
table: 0x20d5690 table: 0x20d5690 table: 0x20d1140

代码思路设计:

1.使用proxy={}空表而不是目标表tbl来设置__newindex是因为__newindex必须在原表里面不存在才会调用,这样就依然可以对已存在的字段进行改写

__newindexThe indexing assignment table[key] = value. Like the index event, this event happens when table is not a table or when key is not present in table. The metamethod is looked up in table.

Like with indexing, the metamethod for this event can be either a function or a table. If it is a function, it is called with tablekey, and value as arguments. If it is a table, Lua does an indexing assignment to this table with the same key and value. (This assignment is regular, not raw, and therefore can trigger another metamethod.)

Whenever there is a __newindex metamethod, Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)

2.避免出现table的互相引用,加入travelled_tables存储已经设置过proxy的table的映射

3.对于原表tbl的访问使用__index=tbl

4.对于表查长度使用__len= function () return #tbl end

5.对于遍历pairs,查到lua5.3的pairs默认迭代器next不支持访问元表__index,故直接__pairs = function () return pairs(tbl) end,以此来生成对目标表的迭代遍历

6.对于ipairs,查到lua5.3 ipairs函数生成的迭代器默认就支持访问元表__index,故不需要添加__ipairs

8.2 – Changes in the Libraries

  • The ipairs iterator now respects metamethods and its __ipairs metamethod has been deprecated.

7.对于table.insert , table.remove不用特殊处理,lua5.3的table lib支持元表操作,故依然会抛错

8.2 – Changes in the Libraries

  • The Table library now respects metamethods for setting and getting elements.

8.避免重复创建read_only,每个tbl只创建一个proxy代理,在tbl的metatable里和proxy的metatable里都设置属性__read_only_proxy,可以直接访问获得

Lua 设置table为只读属性的更多相关文章

  1. lua的table表处理 及注意事项

    lua,一款很轻量级很nice很强大的脚本语言,做为lua中使用最为频繁的table表,在使用之时还是有颇多的好处与坑的: 下面是大牛 云风的一片关于lua table的blog,可使得对lua ta ...

  2. Lua 之table库

    标准table库 table.concat(table, sep,  start, end) concat是concatenate(连锁, 连接)的缩写,table.concat()函数列出参数中指定 ...

  3. lua weak table 概念解析

    lua weak table 经常看到lua表中有 weak table的用法, 例如: weak_table = setmetatable({}, {__mode="v"}) 官 ...

  4. lua中 table 元表中元方法的重构实现

    转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...

  5. lua中 table 重构index/pairs元方法优化table内存占用

    转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...

  6. lua的table元类

    Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表达式a+b.当Lua试图将两个table相加时, ...

  7. lua 的 table 处理

    lua 的整体效率是很高的,其中,它的 table 实现的很巧妙为这个效率贡献很大. lua 的 table 充当了数组和映射表的双重功能,所以在实现时就考虑了这些,让 table 在做数组使用时尽量 ...

  8. 打印Lua的Table对象

    小伙伴们再也不用为打印lua的Table对象而苦恼了, 本人曾也苦恼过,哈哈 不过今天刚完成了这个东西, 以前在网上搜过打印table的脚本,但是都感觉很不理想,于是,自己造轮子了~ 打印的效果,自己 ...

  9. bootstrap Table 中给某一特定值设置table选中

    bootstrap Table 中给某一特定值设置table选中 需求: 如图所示:左边地图人员选定,右边表格相应选中. 功能代码: //表格和图标联动 function changeTableSel ...

随机推荐

  1. App字体大小不随系统改变而改变

    转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6713724.html 在 "设置" , "显示" , " ...

  2. 前端开发必须说的那些事之——同源策略(same origin policy)

    同源策略指的是三个相同 协议相同 域名相同 端口相同 如https://www.baidu.com/hahah.html这个网址来说 https是使用的协议,www.baidu.com是域名,端口号默 ...

  3. python安装win32api pywin32 后出现 ImportError: DLL load failed

    ImportError: DLL load failed: \xd5\xd2\xb2\xbb\xb5\xbd\xd6\xb8\xb6\xa8\xb5\xc4\xc4\xa3\xbf\xe9\xa1\x ...

  4. 关于 centos 7系统,iptables透明网桥实现【转载请注明】

    首先建立网桥:(使用bridge)    示例 桥接eth0 与 eth1 网口 /sbin/modprobe bridge /usr/sbin/brctl addbr br0 /sbin/ifup ...

  5. 跟着刚哥梳理java知识点——反射和代理(十七)

    反射机制是什么?反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有的属性和方法:对于任意一个对象,都能够调用他的一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语 ...

  6. webrtc学习笔记1(建立连接基本流程)

    最近在做一个基于webrtc的视频软件,以下是自己对于上层建立通话连接流程的基本理解,记录于此. 假设A和B要建立视频通话,A为房间创建端,B为加入房间端: 1.A通过http登录.获取其他服务器地址 ...

  7. javaweb项目-医者天下 (Spring+SpringMVC+MyBatis)

    项目下载地址:http://download.csdn.net/detail/qq_33599520/9826683 项目完整结构图: 项目简介: 医者天下项目是一个基于Spring+SpringMV ...

  8. Linux-进程描述(5)之进程环境

    main函数和启动例程 当内核使用一个exec函数执行C程序时,在调用main函数之前先调用一个特殊的启动例程,可执行程序将此例程指定为程序的起始地址.启动例程从内核获取命令行参数和环境变量,然后为调 ...

  9. edge animate从入门到放弃

    一.什么是edge animate edge animate这是一款方便网页设计师和前端工程师实现动画交互的一款工具,虽然是adobe出品的,但是属于Flash和H5时代的过渡产物,这一款产品在201 ...

  10. 蓝桥杯-隔行变色-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...