__index和__newindex都是在table中没有所需访问的index时才发挥作用。

因此,只有将一个table保持为空,才有可能捕捉到所有对它的访问。为了监视一个table的所有访问,就应该为真正的table创建一个代理。

这个代理就是一个空的table,其中__index和__newindex元方法可用于跟踪所有的访问,并将访问重定向到原来的table上。

假设我们要跟踪table t 的访问,可以这样做:

t  = {}          --original table, 在其他地方创建的
local _t = t --保持对原table的一个私有访问
t = {} --创建一个代理
local mt = {
__index = function (t,k)
print("*access to elemet " .. tostring(k))
return _t[k] --访问原table中的k
end
__newindex = function(t,k,v)
print("*update of element" .. tostring(k) .. " to " .. tostring(v))
_t[k] = v --更新原table的值
end
}
setmetatable(t,mt) --将mt设置为 t 的元表

这段代码跟踪了所有对 table t 的访问:

t[] = "hello"              -- *update of element 2 to hello
print(t[]) --> hello -- *access to element 2

但是上面的例子有一个问题,就是无法遍历原来的table。函数pairs只能操作代理table,而无法访问原来的table。

可以通过定义__pairs去遍历:

mt.__pairs = function()
return function(_,k)
return next(_t,k)
end
end

  如果想要同时监视几个table,无须为每个table创建不同的元表。相反,只要以某种形式将每个代理与其原table关联起来,

并且所有代理都共享一个公共的元表。这个问题与前一节所讨论的将table与其默认值相关联的问题类似。

例如将原来table保存在代理table的一个特殊字段中,如下:

local index = {}        --创建私有索引
local mt = { --创建元表
__index = function(t,k)
print("*access to element " .. tostring(k)
return t[index][k] --访问原来的table
end
__newindex = function(t,k,v)
print("*update of element " .. tostring(k) .. " to " .. tostring(v))
t[index][k] = v --更新原来的table
end
__pairs = function(t)
return function(t,k)
return next(t[index],k)
end , t
end
} function track(t)
local proxy= {}
proxy[index] = t
setmetatable(proxy,mt)
return proxy
end

现在,若要监视table t ,唯一要做的就是执行:

t = track(t)

只读的table

  通过代理的概念,可以很容易地就实现出只读的table,只需跟踪所有对table的跟新操作,并引发一个错误就可以了。

由于无须跟踪查询访问,所以对于__index元方法可以直接使用原table来代替函数。这也更简单,并且在重定向所有查询到原table时效率也更高。

不过,这种做法要求为每个只读代理创建一个新的元表,其中__index指向原来的table。

function readOnly(t)
local proxy = {}
local mt = {
__index =t ,
__newindex = function(t,k,v)
error("*attempt to update a read-only table",)
end
}
setmetatable(proxy,mt)
return proxy
end

下面是一个使用的示例,创建了一个表示星期的只读table:

days = readOnly{"Sunday","Monday","Tuesday","Thursday","Friday","Saturday"}
print(days[]) -->Sunday
days[] = "Noday" -- > stdin:1: attempt to update a read-only table

以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition 》

chapter 13_4 跟踪table的访问的更多相关文章

  1. lua的table元类

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

  2. [转]LUA元表

    lua元表和元方法 <lua程序设计> 13章 读书笔记 lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表.lua在 ...

  3. lua元表和元方法 《lua程序设计》 13章 读书笔记

    lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表.lua在创建table时不会创建元表. t = {} print(getmet ...

  4. lua metatable和metamethod元表和元方法

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

  5. Lua 程序设计 (Roberto,Ierusalimschy 著)

    1 开始 2 类型与值 3 表达式 4 语句 5 函数 6 深入函数 7 迭代器与泛型for 8 编译,执行与错误 9 协同程序(coroutine) 10 完整的示例 11 数据结构 12 数据文件 ...

  6. lua学习笔记(八)

      元表与元方法  基本概念         1.lua中每个值都有一个元表         2.table和userdata可以有各自独立的元表         3.其它类型的值共享其类型所属的单一 ...

  7. Step By Step(Lua元表与元方法)

    Step By Step(Lua元表与元方法) Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (45) ------ 第八章 POCO之获取原始对象与手工同步对象图和变化跟踪器

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-6  获取原始对象 问题 你正在使用POCO,想从数据库获取原始对象. 解决方案 ...

  9. Dapper,大规模分布式系统的跟踪系统--转

    原文地址:http://bigbully.github.io/Dapper-translation/ 概述 当代的互联网的服务,通常都是用复杂的.大规模分布式集群来实现的.互联网应用构建在不同的软件模 ...

随机推荐

  1. CODE[VS]-最小数和最大数-整数处理-天梯青铜

    题目描述 Description 输入n个数,n<=100,找到其中最小的数和最大的数 输入描述 Input Description 第一行一个整数n 接下来一行n个整数,每个整数不超过231 ...

  2. linux下使用autoconf制作Makefile

    第一步:常用工具安装:正所谓:"工欲善其事,必先利其器".我们常用的工具主要有GNU AutomakeGNU AutoconfGNU m4GNU Libtool1.查看自己系统中是 ...

  3. DB2的基础指令 学习笔记

    =======DB2基础指令======= 1.打开数据库db2 connect to 数据库名;2.查看数据库中有哪些表db2 list tables ;3.查看数据库中的表结构db2 descri ...

  4. 主题模型 利用gibbslda做数据集主题抽样

    电子科技大学电子商务实验室Kai Yip,欢迎同行指正,也欢迎互相指导,学习. 广告打完,进入正题. 关于程序运行结果的分析请参照我的另一篇博客:http://www.cnblogs.com/nlp- ...

  5. Python基础知识学习_Day1

    1,python介绍 诞生于1989年圣诞节,目前越来越受到业界认可.应用领域十分广泛 云计算: 云计算最火的语言, 典型应用OpenStack WEB开发: 众多优秀的WEB框架,众多大型网站均为P ...

  6. Oracle新实例创建

    http://blog.itpub.net/29519108/viewspace-1443918/ 刚开始创建时,千万别点容器数据库,不然后面新建用户时,用户名前得加C##. 常用命令: sqlplu ...

  7. 小谈数据库Char、VarChar、NVarChar差异

    1. char      固定长度,最长n个字符.   2. varchar      最大长度为n的可变字符串. (n为某一整数,不同数据库,最大长度n不同)   char和varchar区别:   ...

  8. js 常用插件

    文本输入框 计算器 <html> <head> <meta http-equiv="Content-Type" content="text/ ...

  9. Mac下配置Maven环境变量

    Mac下配置Maven环境变量 1.先到Apache官网下载maven压缩包.下载地址:http://maven.apache.org/download.cgi 2.Maven是用Java开发的,所以 ...

  10. Excel 文件转 JSON格式对象

    将导入的如图所示格式的城乡区划代码的excel文件整理成json格式的对象储存在js文件中: var PROJECTDISTRICTDATA=[    {        "name" ...