【游戏开发】小白学Lua——从Lua查找表元素的过程看元表、元方法
引言
在上篇博客中,我们简单地学习了一下Lua的基本语法。其实在Lua中有一个还有一个叫元表的概念,不得不着重地探讨一下。元表在实际地开发中,也是会被极大程度地所使用到。本篇博客,就让我们从Lua查找表元素的过程,来探讨学习一下Lua中的元表。
一、什么是元表
在Lua table中我们可以访问对应的key来得到value值,但是却无法对两个table进行操作。因此Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。通俗来说,元表就像是一个“操作指南”,里面包含了一系列操作的解决方案,例如__index方法就是定义了这个表在索引失败的情况下该怎么办,__add方法就是告诉table在相加的时候应该怎么做。这里面的__index,__add就是元方法,下面我们详细解读一下元方法。
二、什么是元方法
通过上面的知识,我们知道了通过使用元表可以定义Lua如何计算两个table的相加操作。当Lua试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫"__add"的字段,若找到,则调用对应的值。"__add"等即时字段,其对应的值(往往是一个函数或是table)就是"元方法"。很多人对Lua中的元表和元方法都会有一个这样的误解:“如果A的元表是B,那么如果访问了一个A中不存在的成员,就会访问查找B中有没有这个成员”。如果说这样去理解的话,就大错特错了,实际上即使将A的元表设置为B,而且B中也确实有这个成员,返回结果仍然会是nil,原因就是B的__index元方法没有赋值。别忘了我们之前说过的:“元表是一个操作指南”,定义了元表,只是有了操作指南,但不应该在操作指南里面去查找元素,而__index方法则是“操作指南”的“索引失败时该怎么办”。下面我们通过几段实际的代码来看一下Lua的表元素的查找过程以便更深入地体会上述这些概念。
下面是一些Lua表中可以重新定义的元方法:
__add(a, b) --加法
__sub(a, b) --减法
__mul(a, b) --乘法
__div(a, b) --除法
__mod(a, b) --取模
__pow(a, b) --乘幂
__unm(a) --相反数
__concat(a, b) --连接
__len(a) --长度
__eq(a, b) --相等
__lt(a, b) --小于
__le(a, b) --小于等于
__index(a, b) --索引查询
__newindex(a, b, c) --索引更新(PS:不懂的话,后面会有讲)
__call(a, ...) --执行方法调用
__tostring(a) --字符串输出
__metatable --保护元表
三、Lua的表元素查找机制
众所周知,Lua的表本质其实是个类似Dictionary的东西,其元素是很多的Key-Value键值对。如果尝试访问了一个表中并不存在的元素时,就会触发Lua的一套查找机制,Lua也是凭借这个机制来模拟了类似“类”的行为。下面是一段简单地访问表中元素的代码:
myTable = {
prop1 = 'Property',
}
print (myTable.prop1)
print (myTable.prop2) --打印不存在的成员prop2
稍微有些Lua语法的同学,一看就可以看出,上面的输出结果为:Property nil 。输出为nil的原因很简单,myTable中并没有prop2这个成员,这符合我们平时操作Dictionary的习惯。但对于Lua的表,如果myTable有元表和元方法,情况就不同了。下面我们再看一下设置了元表和元方法的代码:
father = {
prop1=
}
son = {
prop2=
}
setmetatable(son, father) --把son的metatable设置为father
print (son.prop1)
执行输出的结果仍然为:nil,这正印证了上面所说的,只设置元表是不管用的。再来看看同时设置元表和对应的元方法的代码:
father = {
prop1=
}
father.__index = father -- 把father的__index方法指向它本身
son = {
prop2=
}
setmetatable(son, father) --把son的metatable设置为father
print (son.prop1)
执行输出的结果为:1。
结合上述的几个小例子,我们再来解释一下__index元方法的含义:在上面的例子中,当访问son.prop1时,son中是没有prop1这个成员的。接着Lua解释器发现son设置了元表:father,(需要注意的是:此时Lua并不是直接在fahter中找到名为prop1的成员,而是先调用father的__index方法),如果__index方法为nil,则直接返回nil。如果__index指向了一张表(上面的例子中father的__index指向了自己本身),那么就会到__index方法所指向的这个表中去查找名为prop1的成员。最终,我们在father表中找到了prop1成员。这里的__index方法除了可以是一个表,也可以是一个函数,如果是函数的话,__index方法被调用时会返回该函数的返回值。
Lua查找一个表元素的规则可以归纳为如下几个步骤:
- Step1:在表自身中查找,如果找到了就返回该元素,如果没找到则执行Step2;
- Step2:判断该表是否有元表(操作指南),如果没有元表,则直接返回nil,如果有元表则继续执行Step3;
- Step3:判断元表是否设置了有关索引失败的指南(__index元方法),如果没有(__index为nil),则直接返回nil;如果有__index方法是一张表,则重复执行Step1->Step2->Step3;如果__index方法是一个函数,则返回该函数的返回值
作者:马三小伙儿
出处:http://www.cnblogs.com/msxh/p/7745553.html
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!
【游戏开发】小白学Lua——从Lua查找表元素的过程看元表、元方法的更多相关文章
- 第十四章 web前端开发小白学爬虫
老猿从事IT开发快三十年了,接触互联网也很久了,但自己没有做过web前端开发,只知道与前端开发相关的一些基本概念,如B/S架构.html标签.js脚本.css样式.xml解析.cookies.http ...
- 【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher
一.简介 最近马三换了一家大公司工作,公司制度规范了一些,因此平时的业余时间多了不少.但是人却懒了下来,最近这一个月都没怎么研究新技术,博客写得也是拖拖拉拉,周六周天就躺尸在家看帖子.看小说,要么就是 ...
- Lua查找表元素过程(元表、__index方法是如何工作的)
近日开始研究Lua,在元表的使用上照猫画虎地搞了两下,实现了“面向对象”,但究其本质却略有不解,后咨询牛哥得解,特此记录. Lua的表本质其实是个类似HashMap的东西,其元素是很多的Key-Val ...
- 第14章 web前端开发小白学爬虫结束语
老猿学爬虫应该是2019年7月初开始的,到现在2个多月了,有段时间了,这部分一直是老猿期待能给大家带来收获的,因为老猿爬虫实战应用的场景与网上老猿已知的场景基本都不一样,是从复用网站登录会话信息来开发 ...
- 【quick-cocos2d-x】Lua 面向对象(OOP)编程与元表元方法
版权声明:本文为博主原创文章,转载请注明出处. 面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物. 早期的计算机编程是基于面向过程的方法,通过设计一个算法就可以解决当时 ...
- 利用Xilinx中的ROM构造查找表来计算sin和cos的方法探讨
1.使用matlab制作.coe文件 查找表的构造 构造256点的正余弦表 exp(-j*2*pi*(0:255)/256),分别得到 cos和sin的查找表 matlab代码: 求sin fid = ...
- cocos游戏开发小白教程网站
<Quick-Cocos2d-x v3.3小白书系列教程> <Quick-Cocos2d-x初学者游戏教程>
- 小白学python-day04-作业-九九乘法表相关
作业内容: 作业一: 作业二: 作业三: (1) (2) \n换行 \t制表符 end="" 代表打印不换行,双引号里面可以在结果之间加字符. print() 代表换行打印,使用时 ...
- 【游戏开发】Excel表格批量转换成lua的转表工具
一.简介 在上篇博客<[游戏开发]Excel表格批量转换成CSV的小工具> 中,我们介绍了如何将策划提供的Excel表格转换为轻便的CSV文件供开发人员使用.实际在Unity开发中,很多游 ...
随机推荐
- java队列
"队列"这个单词是英国人说的"排".在英国"排队"的意思就是站到一排当中去.计算机科学中,队列是一种数据结构,有点类似栈,只是在队列中第一个 ...
- Ribbon整合Eureka组件,以实现负载均衡
1整体框架的说明 在本案例的框架里,我们将配置一个Eureka服务器,搭建三个提供相同服务的Eureka服务提供者,同时在Eureka服务调用者里引入Ribbon组件,这样,当有多个url向服务调用者 ...
- 从前端开发看HTTP协议的应用
一.Chrome Developer Network Tab Cheome Developer作为现在前端开发者最常用的开发调试工具,其具有前端可以涉及到的各方面的强大功能,为我们的开发和定位问题提供 ...
- Colossus: Successor to the Google File System (GFS)
Colossus is the successor to the Google File System (GFS) as mentioned in the recent paper on Spanne ...
- Python 30分钟入门指南
Python 30分钟入门指南 为什么 OIer 要学 Python? Python 语言特性简洁明了,使用 Python 写测试数据生成器和对拍器,比编写 C++ 事半功倍. Python 学习成本 ...
- java之Hibernate框架实现数据库操作
之前我们用一个java类连接MySQL数据库实现了数据库的增删改查操作---------MySQL篇: 但是数据库种类之多,除了MySQL,还有Access.Oracle.DB2等等,而且每种数据库语 ...
- myeclipse 的Customize Perspective 没有反应
MyEclipse 2014 工具栏里的Quick Access老是跳上跳下的,弄得我很烦,所以就想自定义一下工具栏,结果 window--> customize perspective 没用 ...
- visual studio中如何将string类型值转为BYTE(unsigned char)类型
昨天困惑一件事,就是手里有个string类型的字符串,像01 23 45 67 89 AB CD EF,根据空格拆分为一个个的子字符串后(如EF),需要放到一个BYTE(typedef unsigne ...
- PHP_保留两位小数并且四舍五入(可用于精度计算)_保留两位小数并且不四舍五入
小数例子: PHP保留两位小数并且四舍五入 1 $n=0.1265489; 2 echo sprintf("%.2f", $n); // 0.13 大家可以看到我们用到了sprin ...
- tomcat启动报错:Address already in use: JVM_Bind
tomcat启动时出现Address already in use: JVM_Bind 的原因是因为端口被占用,有可能是因为多次启动tomcat或者启动了多个tomcat,或者是其他应用程序或者服务占 ...