Lua中__index和__newindex实践

具有默认值的table

我们都知道,table中的任何字段的默认值都是nil,但是通过元表,我们可以很容易的修改这一规定,代码如下:

function setDefault(tb, defaultValue)

     local mt = {__index = function () returndefaultValue end}

     setmetatable(tb, mt)

end


local tb1 = {x = 10, y = 20}

print(tb1.x, tb1.z)     --> 10 nil

setDefault(tb1, 100) -->设置默认值

print(tb1.x, tb1.z) --> 10 100 这里打印的就是默认值



可以看到,在代码中,setDefault函数为所有需要默认值的table创建了一个新的元表。如果准备创建很多需要默认值得table,这种方法的开销或许就比较大了。由于在元表中默认值defaultValue是与元方法关联在一起的,所以setDefault无法为所有table都使用同一个元表。如果要让具有不同默认值得table都使用同一个元表,那么就需要将每个元表的默认值存放在table本身中,可以使用一个额外的字段来存储默认值。例如以下代码:

local mt = {__index = function (t) returnt.___ end}

function setDefault(tb, defaultValue)

     tb.___ = defaultValue       -- 非常谢谢hellowei犀利的review。具体请参见评论

     setmetatable(tb, mt)

end



上面代码中的“___”是为了防止名字冲突而起的名字;如果这样的话,你还担心名字冲突,确保key在table中的唯一性,只需要创建一个新的table,并用它作为key即可,每一个新创建的table都是一个唯一的地址,比如以下代码:

local key = {} -- 唯一的key

local mt = {__index = function (tb) returntb[key] end}


function setDefault(tb, defaultValue)

     tb[key] = defaultValue

     setmetatable(tb, mt)

end


 

记录table的访问

有的时候,一种特定的需求,我们需要记录对一个table的所有访问,不管是查询还是更新,我们都需要记录日志。这如何完成?我们都知道,元表中的__index和__newindex是在table中没有所需要访问的index时才发挥作用的,因此,只有将一个table保持为空,然后设置__index和__newindex元方法,才有可能记录下来所有对它的访问。


为了监视一个table的所有访问,就应该为真正的table创建一个代理。这个代理就是一个空的table,其中__index和__newindex元方法可用于跟踪所有的访问,并将访问重定义到原来的table上。这就是思路,接下来看代码:

local t = {} --原来的table


-- 保持对原table的一个引用

local _t = t


-- 创建代理

t = {}


-- 创建元表

local mt = {

__index = function (t, k)

print("access to element ".. tostring(k))

return_t[k]

end,


__newindex = function (t, k, v)

print("update of element ".. tostring(k))

_t[k] = v

end

}


setmetatable(t, mt)


t.x = 10 -- update of element x

print(t.x) -- access to element x


如果想要同时监视几个table,无须为每个table创建不同的元表;相反,只要以某种形式将每个代理与其原table关联起来,并且所有代理都共享一个公共的元表。这个问题与设置table默认值相关联的问题类似,也是将原来的table保存在代理table的一个特殊的字段中。代码如下:

-- 创建唯一索引

local index = {}


-- 创建元表

local mt = {

     __index = function (t, k)

          print("access to element ".. tostring(k))

          returnt[index][k]

     end,


     __newindex = function (t, k, v)

          print("update of element ".. tostring(k))

          t[index][k] = v

     end

}


function track(t)

     local proxy = {}

     proxy[index] = t

     setmetatable(proxy, mt)

     returnproxy

end


local t = {}

local proxy = track(t)

proxy.x = 10

print(proxy.x)


只读的table

通过代理的概念,可以很容易的实现只读的table。只需要跟踪所有对table的更新操作,并引发一个错误就好了,对于查询时,我们不用去馆,只需要管对table的更新操作,废话不说,来段简单的代码,自然而然的一目了然了。

function readOnly(t)

     local proxy = {}


     -- 创建元表

     local mt = {

          __index = t,

          __newindex = function (t, k, v)

               error("Attempt to update a read-only table", 2)

          end

     }


     setmetatable(proxy, mt)

     returnproxy

end


local tbDemo = readOnly{1, 2, 3, 4, 5}

print(tbDemo[1])

tbDemo[1] = 20


元表中__index对应的是原来的table,而更新原来的table时,就会显示错误提示:Attempt to update a read-only table。


总结

这篇文章对Lua中的__index和__newindex的使用进行了详细的讲解和分析,并提供了实际的代码,主要是为了加深对Lua中元表和元方法的理解,元表和元方法在Lua中的地位太总要了,很多高级的编程技巧和特殊需求都是基于元表和元方法来实现了,所以,也希望大家能好好的阅读这篇文章,同时也希望我的文章对大家有帮助。


来源网址:http://www.jellythink.com/archives/517

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,373评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,732评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,163评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,700评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,036评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,425评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,737评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,421评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,141评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,398评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,908评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,276评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,907评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,018评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,772评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,448评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,325评论 2 261

推荐阅读更多精彩内容