Lua 设置table为只读属性
如果转载,请注明博文来源: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必须在原表里面不存在才会调用,这样就依然可以对已存在的字段进行改写
__newindex: The indexing assignmenttable[key] = value. Like the index event, this event happens whentableis not a table or whenkeyis not present intable. The metamethod is looked up intable.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
table,key, andvalueas 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
__newindexmetamethod, Lua does not perform the primitive assignment. (If necessary, the metamethod itself can callrawsetto 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
ipairsiterator now respects metamethods and its__ipairsmetamethod 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为只读属性的更多相关文章
- lua的table表处理 及注意事项
lua,一款很轻量级很nice很强大的脚本语言,做为lua中使用最为频繁的table表,在使用之时还是有颇多的好处与坑的: 下面是大牛 云风的一片关于lua table的blog,可使得对lua ta ...
- Lua 之table库
标准table库 table.concat(table, sep, start, end) concat是concatenate(连锁, 连接)的缩写,table.concat()函数列出参数中指定 ...
- lua weak table 概念解析
lua weak table 经常看到lua表中有 weak table的用法, 例如: weak_table = setmetatable({}, {__mode="v"}) 官 ...
- lua中 table 元表中元方法的重构实现
转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...
- lua中 table 重构index/pairs元方法优化table内存占用
转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...
- lua的table元类
Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表达式a+b.当Lua试图将两个table相加时, ...
- lua 的 table 处理
lua 的整体效率是很高的,其中,它的 table 实现的很巧妙为这个效率贡献很大. lua 的 table 充当了数组和映射表的双重功能,所以在实现时就考虑了这些,让 table 在做数组使用时尽量 ...
- 打印Lua的Table对象
小伙伴们再也不用为打印lua的Table对象而苦恼了, 本人曾也苦恼过,哈哈 不过今天刚完成了这个东西, 以前在网上搜过打印table的脚本,但是都感觉很不理想,于是,自己造轮子了~ 打印的效果,自己 ...
- bootstrap Table 中给某一特定值设置table选中
bootstrap Table 中给某一特定值设置table选中 需求: 如图所示:左边地图人员选定,右边表格相应选中. 功能代码: //表格和图标联动 function changeTableSel ...
随机推荐
- AFNetworking 用法详解
之前一直使用ASIHttpRequest 做网络请求 ,后来新公司用AFNetWorking ,经过一段时间学习总结一下二者的优缺点: 1.AFNetWorking的优缺点 优点: 1.维护和使用者比 ...
- iOS多线程的三种方法
前言 在多线程简介中,我已经说明过了,为了提高界面的流畅度以及用户体验.我们务必要把耗时的操作放到别的线程中去执行,千万不要阻塞主线程.iOS中有以下3种多线程编程方法: NSThread Grand ...
- 如何有效快速提高Java服务端开发人员的技术水平?
我相信很多工作了3-5年的开发人员都会经常问自己几个问题: 1.为什么总是感觉技术没有质的提高? 2.如何能够有效和快速的提高自身的技术水平? 3.如何进入到一个牛逼的大公司,认识牛逼的人? 这篇文章 ...
- 开发Angular库的简单指导(译)
1. 最近工作上用到Angular,需要查阅一些英文资料,虽然英文非常烂,但是种种原因又不得不硬着头皮上,只是每次看英文都很费力,因此决定将一些比较重要的特别是需要反复阅读的资料翻译一下,以节约再次阅 ...
- 《Effective C#》读书笔记-1.C# 语言习惯-1.使用属性而不是可访问的数据成员
思维导图: 大纲: 1.使用属性而不是可访问的数据成员 属性 指定不同的访问权限 隐式属性降低了声明属性的工作量 允许将数据成员作为公共接口的一部分暴露 ...
- CSS表单属性
一般来说,表单在一个页面中是必不可少的,下面是我对表单的知识总结: 依次要说的是表单元素.表单属性.以及表单提交(js知识) 1,表单元素: <form action="提交的位置 / ...
- 防止微信浏览器video标签全屏的问题
在微信浏览器里面使用video标签,会自动变成全屏,改成下面就好了,起码可以在video标签之上加入其他元素. <video id="videoID" webkit-play ...
- xmlplus 组件设计系列之六 - 下拉刷新
"下拉刷新"由著名设计师 Loren Brichter 设计,并应用于 Twitter 第三方应用 Tweetie 中.2010年4月,Twitter 收购 Tweetie 开发商 ...
- 微信小程序后台音乐播放注意事项
wx.seekBackgroundAudio(OBJECT) 作用:控制音乐播放进度. 注意: 该事件 会触发 wx.onBackgroundAudioPlay(CALLBACK) 事件 ,也就是相当 ...
- Windows系统操作指令汇总
CMD命令:开始->运行->键入cmd或command(在命令行里可以看到系统版本.文件系统版本) 1. appwiz.cpl:程序和功能 2. calc:启动计算器 3. certmgr ...