Lua高级教程Metatables
什么是Metatable
metatable是Lua中的重要概念,每一个table都可以加上metatable,以改变相应的table的行为。
Metatables举例

-- 声明一个正常的关系变量
lo_table = {} -- 声明空元表变量
lo_meta_table = {} -- 为关系变量t设置元表变量
setmetatable(lo_table, lo_meta_table) -- 获取一个关系变量的元表变量
getmetatable(lo_table)

上边的代码也可以写成一行,如下所示
-- setmetatable函数的返回值,就是该函数的第一个参数
lo_table = setmetatable({}, {})
创建复杂的元表变量
metatable可以包括任何东西,metatable特有的键一般以__开头,例如__index和__newindex,它们的值一般是函数或其他table。

lo_table = setmetatable({}, {
__index = function(lo_table, key)
if key == "foo" then
return 0
else
return table[key]
end
end
})

__index
这是metatable最常用的键了。
当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index键。如果__index包含一个表格,Lua会在表格中查找相应的键。

-- 创建元表变量
lo_meta_table = { name = "蓝鸥" } -- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __index = lo_meta_table }) -- 打印lo_table变量的姓名 蓝鸥
print(lo_table.name) -- 打印lo_table变量年龄 nil
print(lo_table.age)

如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。

-- 创建元表变量
lo_meta_table = {
name = "蓝鸥" ,
action = function ( param )
-- body
if(param == "学生") then
print("让教育回归本质")
else
print("让蓝鸥维护教育")
end
end
} -- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __index = lo_meta_table }) -- 打印lo_table变量的动作 让教育回归本质
print(lo_table.action("学生")) -- 打印lo_table变量的动作 让蓝鸥维护教育
print(lo_table.action("肖浩")) -- 打印lo_table变量年龄 nil
print(lo_table.age)

__newindex
类似__index,__newindex的值为函数或table,用于按键赋值的情况。

-- 创建元表变量
lo_meta_table = {} -- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __newindex = lo_meta_table }) -- 设置lo_table变量的name关键字的值
lo_table.name = "蓝鸥" -- 打印lo_meta_table元表变量name关键字的值值
print(lo_meta_table.name) -- 打印lo_table变量name关键字的值
print(lo_table.name)


-- 创建元表变量
lo_meta_table = {} -- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __newindex = function(t, key, value)
if type(value) == "number" then
rawset(t, key, value * value)
else
rawset(t, key, value)
end
end
}) -- 设置lo_table变量的name关键字的值
lo_table.name = "蓝鸥" -- 设置lo_table变量的age关键字的值
lo_table.age = 3 -- 打印lo_meta_table元表变量name关键字的值值
print(lo_meta_table.name) -- 打印lo_table变量name关键字的值
print(lo_table.name) -- 打印lo_meta_table元表变量age关键字的值值
print(lo_meta_table.age) -- 打印lo_table变量age关键字的值
print(lo_table.age)

上面的代码中使用了rawget和rawset以避免死循环。使用这两个函数,可以避免Lua使用__index和__newindex。
运算符
利用metatable可以定义运算符,例如+:

-- 创建重载+号行为的表变量
lo_table = setmetatable({ 1, 2, 3 }, {
__add = function(lo_table, other)
new = {} -- 遍历元素加other
for _, v in ipairs(lo_table)
do table.insert(new, v + other)
end return new
end
}) -- 进行计算+
lo_table = lo_table + 2 -- 打印得到的结果
print(lo_table[1])
print(lo_table[2])
print(lo_table[3])

和__index、__newindex不同,__mul的值只能是函数。与__mul类似的键有:
__add(+)__sub(-)__div(/)__mod(%)__unm取负__concat(..)__eq(==)__lt(<)__le(<=)
__call
__call使得你可以像调用函数一样调用table

t = setmetatable({}, {
__call = function(t, a, b, c, whatever)
return (a + b + c) * whatever
end
})
local result = t(1, 2, 3, 4)
print(result)

__tostring
最后讲下__tostring,它可以定义如何将一个table转换成字符串,经常和 print 配合使用,因为默认情况下,你打印table的时候会显示 table: 0x7f86f3d04d80 这样的代码

lo_table = setmetatable({ 1, 2, 3 }, {
__tostring = function(lo_table)
sum = 0
for _, v in pairs(lo_table)
do
sum = sum + v
end
return "计算的结果是: " .. sum
end
})
-- prints out "计算的结果是: 6"
print(lo_table)

创建一个简单的向量Vector类

Vector = {}
Vector.__index = Vector
function Vector.new(x, y)
return setmetatable({ x = x or 0, y = y or 0 }, Vector)
end
-- __call关键字
setmetatable(Vector, { __call = function(_, ...) return Vector.new(...) end })
-- + 运算符
function Vector:__add(other)
-- ...
local result = Vector(self.x + other.x,self.y + other.y)
return result
end
-- __tostring关键字
function Vector:__tostring()
-- body
return "x: " .. self.x .. " y: " .. self.y
end
a = Vector.new(12, 10)
b = Vector(20, 11)
c = a + b
print(a)
print(c)

转自:http://www.cnblogs.com/daxiaxiaohao/p/4651767.html
Lua高级教程Metatables的更多相关文章
- [Lua]Lua高级教程Metatables
什么是Metatable metatable是Lua中的重要概念,每一个table都可以加上metatable,以改变相应的table的行为. Metatables举例 -- 声明一个正常的关系变量 ...
- ios cocopods 安装使用及高级教程
CocoaPods简介 每种语言发展到一个阶段,就会出现相应的依赖管理工具,例如Java语言的Maven,nodejs的npm.随着iOS开发者的增多,业界也出现了为iOS程序提供依赖管理的工具,它的 ...
- 【读书笔记】.Net并行编程高级教程(二)-- 任务并行
前面一篇提到例子都是数据并行,但这并不是并行化的唯一形式,在.Net4之前,必须要创建多个线程或者线程池来利用多核技术.现在只需要使用新的Task实例就可以通过更简单的代码解决命令式任务并行问题. 1 ...
- 【读书笔记】.Net并行编程高级教程--Parallel
一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机 ...
- 分享25个新鲜出炉的 Photoshop 高级教程
网络上众多优秀的 Photoshop 实例教程是提高 Photoshop 技能的最佳学习途径.今天,我向大家分享25个新鲜出炉的 Photoshop 高级教程,提高你的设计技巧,制作时尚的图片效果.这 ...
- 展讯NAND Flash高级教程【转】
转自:http://wenku.baidu.com/view/d236e6727fd5360cba1adb9e.html 展讯NAND Flash高级教程
- 转:Lua简明教程
需要注意的是:lua中的变量如果没有特殊说明,全是全局变量,那怕是语句块或是函数里. 这里很奇怪,为什么在函数内部声明的变量默认也是global的呢? 函数的返回值 和Go语言一样,可以一条语句上赋多 ...
- Net并行编程高级教程--Parallel
Net并行编程高级教程--Parallel 一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控 ...
- [转帖]tar高级教程:增量备份、定时备份、网络备份
tar高级教程:增量备份.定时备份.网络备份 作者: lesca 分类: Tutorials, Ubuntu 发布时间: 2012-03-01 11:42 ė浏览 27,065 次 61条评论 一.概 ...
随机推荐
- radio里面value值与其他字符进行比较
本题旨在创建一个具有及时反馈的选择题,当选完其中一个选项后,会有弹窗来提醒你选择的答案是正确还是错误的.<div id="text" style="display: ...
- PAT甲级训练刷题代码记录
刷题链接:https://www.patest.cn/contests/pat-a-practise 1001 #include <iostream> #include <stdio ...
- ios_swift开发资源整理
目录 1.苹果官方资源 2.国内外视频网站推荐 3.中文文档 4.demo网站 5.开发工具推荐 6.国内外开发网站论坛 7.技术博客推荐 8.书籍推荐 9.第三方框架推荐 10.第三方发布平台 11 ...
- 在Freeplane中显示与隐藏层级图标
如下图所示,当选择了Edit → Icons → Show icons hierarchically时,给子节点Subsection 1.2.1添加的图标也同样会显示在其所有的父节点上,并且,它们并不 ...
- IIS添加服务
最近心血来潮,想学习一下WCF,看着网上的一个小例子就开始动手了. 写了一个简单的服务,准备发布时,才发现很多问题,根本不能像网上的那些大神一样“易得”. 其中遇到的一个的典型问题,就是提示为下载的文 ...
- Java 并发 线程的优先级
Java 并发 线程的优先级 @author ixenos 低优先级线程的执行时刻 1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止.退出或者由于 ...
- Struts2 注解零配置方法(convention插件使用)
最近接触到一个新的项目,是做一个使用S2SH的电子商务商城的二次开发.之前使用过S2SH,在此之前的项目中,Struts2 使用的是XML配置而这个项目是使用注解.在这个项目中,注解还不需要使用Act ...
- iOS混合应用开发入门
原文出处: cocoacontrols 译文出处:魏志峰(@JeremyWei) 欢迎分享原创到伯乐头条 http://blog.jobbole.com/46554/ 介绍 上周(译者:原文成 ...
- put a favicon for github pages
put the picture "favicon.ico" in the root of your web page repo.then add the following lin ...
- EBS FORM FOLDER 开发,单元格无法使用右键
问题描述: 在使用folder开发FORM后,单元格无法使用右键,正常应该可以右键进行隐藏.显示.复制等操作. 通过对比发现是因ITEM属性中 弹出式菜单未设置导致. 解决方法: 设置弹出式菜单