文档章节

[Lua]Lua高级教程Metatables

浩浩老师
 浩浩老师
发布于 2015/10/20 14:15
字数 1041
阅读 183
收藏 3

阿里云携手百名商业领袖、技术大咖,带您一探行进中的数字新基建!>>>

什么是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

浩浩老师
粉丝 1
博文 80
码字总数 0
作品 0
海淀
程序员
私信 提问
加载中

评论(0)

【Lua高级教程】什么是Metatable举例说明

什么是Metatable metatable是Lua中的重要概念,每一个table都可以加上metatable,以改变相应的table的行为。 Metatables举例 lotable =lometatable =(lotable) 上边的代码也可以写成一行,如...

浩浩老师
2015/09/08
148
0
Lua一系列很好的技术分享文章链接: 快速掌握 Lua 5.3

Lua一系列很好的技术分享文章链接: 快速掌握 Lua 5.3 --- 该系列文章作者: VermillionTear 作者博客专栏: 快速掌握Lua 5.3(http://blog.csdn.net/column/details/quicklymasterlua5-3.html)...

FreeBlues
2016/05/29
158
2
Lua笔记——3.元表Metatable

metatable简介1.在Lua 中每个 value( table 和 userdata ) 都可以有一个属于自己的 metatable,相同类型的value共享一个属于本类型的 metatable。初始情况下,string 类型有自己的 metatabl...

osc_lbsmihm9
2018/02/27
4
0
Redis结合Lua脚本实现高并发原子性操作

从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis … 非脚本实现 以上代码有两点缺陷 可能会出现竞态条件: 解决方法是用 监控 的变动, 但较为麻烦; 以上代码在不使用 的情况下...

osc_c0r2dsk1
2018/03/13
2
0
Lua语言模型 与 Redis应用

Lua语言模型 与 Redis应用 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis. 本篇博客主要介绍了 Lua 语言不一样的设计模型(相比于Java/C/C++、JS、PHP),...

菜鸟-翡青
2016/10/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

URL 中文链接 编码错误 完美解决

直接上代码 str = "%25E4%25B8%25AD%25E6%2596%2587";console.log(str);str =decodeURIComponent(decodeURIComponent(str));console.log(str); 输出结果 %25E4%25B8%25AD%25E6%2596%25......

放只虎归个山
39分钟前
17
0
.NET中小数,浮点数和双精度之间的区别? - Difference between decimal, float and double in .NET?

问题: What is the difference between decimal , float and double in .NET? .NET中的decimal , float和double float什么区别? When would someone use one of these? 有人什么时候会使用......

fyin1314
今天
22
0
如何找出Windows上正在侦听端口的进程? - How can you find out which process is listening on a port on Windows?

问题: 如何找出Windows上正在侦听端口的进程? 解决方案: 参考一: https://stackoom.com/question/CXO/如何找出Windows上正在侦听端口的进程 参考二: https://oldbug.net/q/CXO/How-can...

技术盛宴
今天
10
0
OSChina 周三乱弹 —— 一家动物都快饿成标本了~

@黑觉非常君 :前天晚上9点开始睡觉,睡到昨天上午8点起床,昨天下午2点又睡,睡到下午7点多,晚上10点又困了,又睡,睡到今天上午8点,中途没醒过,怎么这么能睡,是不是快挂了。 能睡不是好...

小小编辑
今天
24
0
神剧推荐全剧最污片段精剪

神剧推荐,全剧最污片段精剪 豆瓣评分最高,脑洞最大,脑回路最曲折,恶搞无数经典,没有一条差评的神剧 整个系列完整版 到这里观看

a57571735
今天
22
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部