前两节的算术类、关系类运算符的元方法都为各种错误情况定义了行为,它们不会改变语言的常规行为。

但是Lua还提供了两种可以改变table行为的方法:

一种是查询table中不存在的字段、一种是修改table中不存在的字段。

__index元方法

当访问一个table中不存在的字段时,得到的结果为nil。这样的访问会促使解释器去查找一个叫__index的元方法。

如果没有这个元方法,那么访问结果就是nil。

一个有关继承的示例:假设要创建一些描述窗口的table,每个table中必须表述一些窗口参数,如:位置、大小、主题....

所有这些参数都有默认值,因此希望在创建窗口对象时可以仅提供那些不同于默认值的参数。

第一种方法是使用一个构造式,在其中填写那些不存在的字段。

第二种方法是让新窗口从一个原型窗口处继承所有不存在的字段。

首先,声明一个原型和一个构造函数,构造函数创建新的窗口,并使它们共享同一个元表:

prototype = {x = , y = ,width =  , height  = } --用默认值来创建一个原型
mt = {} --创建一个元表
function new(o) --声明构造函数
setmetatable(o,mt)
return o
end

现在,定义__index元方法:

mt.__index = function(_,key)
return prototype[key]
end

在这段代码之后,创建一个新窗口,并查询一个它没有的字段:

w = new{x=,y=}
print(w.width) -->100

若Lua检测到w中没有width字段,但在其元素中却有一个__index字段,那么Lua就会以 w 和 “width” 来调用这个__index元方法。

随后元方法用这个key来索引原型table,并返回结果。

在Lua中,将__index元方法用于继承是很普遍的方法,因此Lua还提供了一种更便捷的方式来实现此功能。

__index不一定是一个函数,可以是一个table。

当它是一个table时,Lua就以相同的方式来重新访问这个table。因此,上面的__index的声明可以写为:

mt.__index = prototype

现在,Lua查到元素__index时,发现它是一个table,那么Lua就会在prototype中继续查找。

也就是说,Lua会在这个table中国重复这个访问过程:类似于这样访问

prototype["width"]

这样将一个table作为__index元方法 是快捷的、实现单一继承的方式。虽然用函数更加灵活,但是开销较大。

可以通过函数来实现多重继承、缓存及其他一些功能。

如果不想在访问一个table时涉及到它的__index元方法,可以使用rawget函数。

调用rawget(t , i) 就是对table t 进行了一个原始的访问。

__newindex元方法

它与__index类似,不同之处在于它用于table的更新,而__index用于table的查询。

当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法。如果有这个元方法,解释器就调用它,而不是执行赋值。

如果这个元方法是一个table,解释器就在此table中执行赋值,而不是对原来的table。

也可以通过rawset( t ,k , v )来绕过元方法,直接设置table  t 中与key k 相关联的value v

组合使用__index和__newindex元方法就可以实现出Lua中的一些强大功能,例如:

只读的table、具有默认值的table、面向对象编程中的继承。

具有默认值的table

常规table中的任何字段默认值都是nil,通过元表就可以很容易地修改这个默认值:

function setDefault(t,d)
local mt = {__index = function() return d end}
setmetatable(t,mt)
end tab = {x=,y=}
print(tab.x,tab.z) --> 10 nil
setDefault(tab, )
print(tab.x,tab.z) -->10 1

在调用setDefault后,任何对tab中不存在的访问都将调用它的__index元方法,而这个元方法会返回d的值。

setDefault函数为所有需要默认值的table创建了一个新的元素。

如果准备创建很多需要默认值的table,这个开销比较大。

由于在元表中默认值d是与元方法关联在一起的,所以setDefault无法为所有table都使用同一个元表。

若要让具有不同默认值的table都使用同一个元表,那么需要将每个元表的默认值都放到table本身中。

可以使用一个额外的字段来保存默认值。避免冲突,可以使用"___"这样的key作为额外的字段:

local mt = {__index = funxtion (t) return t.___ end}
function setDefault(t, d )
t.___ = d
setmetatable(t,mt)
end

如果担心名称冲突,那么要确保这个特殊key的唯一性也很容易,只需创建一个新的额table,并用它作为key即可:

local key = {}  --唯一的key
local mt = {__index = function(t) return t[key] end}
function setDefault(t , d)
t[key] =d
setmetatable(t,mt)
end

还有一种方法可以将table与其默认值关联起来:使用一个独立的table,它的key为各种table,value就是各种table的默认值。

不过,为了正确地实现这种做法,需要一种特殊性质的table,就是“弱引用table”。

还有一种备忘录元表的方法,它能使具有相同默认值的table复用同一个元表,也需要用到弱引用table。以后会讲到.....

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

chapter 13_3 table访问的元方法的更多相关文章

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

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

  2. chapter 13_1 算术类的元方法

    假设用table来表示集合,用function去计算集合的交集.并集. 为了保持名称空间的整齐,将这些函数存入一个名为Set的table中. 现在,假设用“+”来计算两个集合的并集,那么就要让所有用于 ...

  3. Lua 学习笔记(十一)元表与元方法

    在Lua中的每个值都有一套预定义的操作集合.例如可以将数字相加,可以连接字符串,还可以在table中插入一对key-value等.但是我们无法将两个table相加,无法对函数作比较,也无法调用一个字符 ...

  4. lua元表与元方法

    lua中提供的元表(metatable)与元方法(metamethod)是一种非常重要的语法,metatable主要用于做一些类似于C++重载操作符式的功能. lua中提供的元表是用于帮助lua变量完 ...

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

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

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

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

  7. lua元表(metatable)和元方法(metamethod)

    (一) 元表概念: 引言:Lua中的每个值都有一套预定义的操作集合,如数字相加等.但无法将两个table相加,此时可通过元表修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定操作. 访问机制 ...

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

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

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

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

随机推荐

  1. javascript入门基础知识

    JavaScript介绍: 1. javascrip是互联网上最流行的脚本语言,可用于Web和HTML,更可广泛用于服务器.pc端.移动端. 2. javascript脚本语言: javascript ...

  2. DUIlib使用Fastreport--自定义的数据

    报表根据数据源的可以分为拉模式和推模式,拉模式就是在报表中添加数据源组件从数据库中拉取数据,我们上篇报表的简单使用就是拉模式.而推模式就是在程序中构造数据托给报表显示.这篇我们这要说的是推模式. 在程 ...

  3. Html5移动端页面自适应百分比布局

    按百分比布局,精度肯定不会有rem精确 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  4. jenkins jmeter持续集成批处理jmx脚本

    这篇文章介绍jenkis jmeter的持续集成,利用jenkins定时任务去批处理执行jmeter的jmx脚本文件,并且生成测试报告 1:jmeter的安装这里我就不在赘述了,如有问题可参考我的jm ...

  5. Vim/gvim容易忘记的快捷键

    正常模式==>插入模式 按i 在光标前插入 按I 在行首插入 按a 在光标后插入 按s 删除光标所在的字符再插入 按A 在行末插入 按o 在当前行之下新建行 按O 在当前行之上新建行 按S 删除 ...

  6. java 缩放函数drawImage理解(个人总结)

    drawImagepublic abstract boolean drawImage(Image img,                                  int dx1,      ...

  7. SQLite模糊查找(like)

    select UserId,UserName,Name,Sex,Birthday,Height,Weight,Role from xqhit_Users where UserName like &qu ...

  8. Ubantu安装mysql

    在Linux下MySQL的安装,我一直觉得挺麻烦的,因为之前安装时就是由于复杂的配置导致有点晕.今天,需要在Linux下用Qt连接MySQL.遂安装配置了一把. 1)首先检查系统中是否已经安装了MyS ...

  9. 元素的BFC特性与自适应布局

    一.BFC元素简介与基本表现. BFC全程"Block Formatting Context",中文为"块级格式化上下文".记住一句话:BFC元素特性表现原则就 ...

  10. NYOJ-1057 寻找最大数(三)(贪心)

    寻找最大数(三) 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 给出一个整数N,每次可以移动2个相邻数位上的数字,最多移动K次,得到一个新的整数. 求这个新的整数的 ...