如果转载,请注明博文来源: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. Hibernate基础学习(六)—Hibernate二级缓存

    一.概述      Session的缓存是一块内存空间,在这个内存空间存放了相互关联的Java对象,这个位于Session缓存内的对象也被称为持久化对象,Session负责根据持久化对象的状态来同步更 ...

  2. [笔记]RankSVM 和 IR SVM

    之前的博客:http://www.cnblogs.com/bentuwuying/p/6681943.html中简单介绍了Learning to Rank的基本原理,也讲到了Learning to R ...

  3. You-Get , A Tiny Downloader,视频下载小工具

    ---恢复内容开始--- You-Get    You-Get is a tiny command-line utility to download media contents (videos, a ...

  4. SQL Server 中截取字符串常用的函数

    SQL Server 中截取字符串常用的函数: 1.LEFT ( character_expression , integer_expression ) 函数说明:LEFT ( '源字符串' , '要 ...

  5. 【小瑕疵】表单中的button会自动提交?

    在表单中使用button标签的时候会发现,即使什么类型都没有设置,但是在点击的时候会发现,表单会自动提交 比如: 我在一个表单的button中添加一个函数,当点击这个按钮时会增加一行内容: 但是当我实 ...

  6. Java 工具类—日期获得,随机数,系统命令,数据类型转换

    package tems; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; ...

  7. IOS中的通知NSNotification

    类似于Android中的广播接收者发送者 1.一般完整的通知包含三个属性 -(NSString *)name ;//通知的名称 -(id)object ;//通知发布者(是谁要发布通知) -(NSDi ...

  8. java集合系列—ArrayList

    ArrayList是工作以来使用频率最高的集合类.以前上课老师说不知道用什么集合类就用ArrayList,好吧,后面就这样了. public class ArrayList<E> exte ...

  9. C#集合之有序列表

    如果需要基于键对所需集合排序,就可以使用SortedList<TKey,TValue>类.这个类按照键给元素排序.这个集合中的值和键都可以使用任何类型.定义为键的自定义类型需要实现ICom ...

  10. RNN的介绍

    一.状态和模型 在CNN网络中的训练样本的数据为IID数据(独立同分布数据),所解决的问题也是分类问题或者回归问题或者是特征表达问题.但更多的数据是不满足IID的,如语言翻译,自动文本生成.它们是一个 ...