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

lua中提供的元表是用于帮助lua变量完成某些非预定义功能的个性化行为,如两个table的相加,通过让两者指向同一元表并修改该元表的元方法可以实现该功能。

任何table都可以成为任何值的元表,而一组相关的table也可以共享一个元表。

一些MetaMethod:

  1. __add(a, b) 对应表达式 a + b
  2. __sub(a, b) 对应表达式 a - b
  3. __mul(a, b) 对应表达式 a * b
  4. __div(a, b) 对应表达式 a / b
  5. __mod(a, b) 对应表达式 a % b
  6. __pow(a, b) 对应表达式 a ^ b
  7. __unm(a) 对应表达式 -a
  8. __concat(a, b) 对应表达式 a .. b
  9. __len(a) 对应表达式 #a
  10. __eq(a, b) 对应表达式 a == b
  11. __lt(a, b) 对应表达式 a < b
  12. __le(a, b) 对应表达式 a <= b
  13. __index(a, b) 对应表达式 a.b
  14. __newindex(a, b, c) 对应表达式 a.b = c
  15. __call(a, ...) 对应表达式 a(...)

1、算术类and关系类元方法

先看一个简单的例子:

  1. --我们想让两个分数相加,这是一种非预定义的行为
  2.  
  3. fraction_a = {numerator=, denominator=}
  4. fraction_b = {numerator=, denominator=}
  5. fraction_op={} --元表
  6.  
  7. -- __add这是metatable,这是lua内建约定的
  8. function fraction_op.__add(a,b)
  9. res={}
  10. res.numerator=a.numerator*b.denominator+b.numerator*a.denominator
  11. res.denominator=a.denominator*b.denominator
  12. return res
  13. end
  14.  
  15. --将fraction_afraction_b的元表设置为fraction_op
  16. --其中setmetatable是库函数
  17. setmetatable(fraction_a,fraction_op)
  18. setmetatable(fraction_b,fraction_op)
  19.  
  20. --调用的是fraction_op.__add()函数
  21. fraction_c=fraction_a+fraction_b
  22. print(fraction_c.numerator.."/"..fraction_c.denominator)
  23. --输出结果
  24. --26/21

再来看一个深度一点的例子,例举了算数类的元方法,关系类的元方法,库定义的元方法。

  1. Set={}
  2.  
  3. local metatable={} --元表
  4.  
  5. --根据参数列表中的值创建一个新的集合
  6. function Set.new(a)
  7. local set={}
  8. --将所有由该方法创建的集合的元表都指定到metatable
  9. setmetatable(set,metatable)
  10. for i,v in pairs(a) do
  11. set[v]=true
  12. end
  13. return set
  14. end
  15.  
  16. --计算两个集合的并集
  17. function Set.union(a,b)
  18. local res=Set.new{}
  19. for i in pairs(a) do
  20. res[i]=true
  21. end
  22. for i in pairs(b) do
  23. res[i]=true
  24. end
  25. return res
  26. end
  27.  
  28. --计算两个集合的交集
  29. function Set.intersect(a,b)
  30. local res=Set.new{}
  31. for i in pairs(a) do
  32. res[i]=b[i]
  33. end
  34. return res
  35. end
  36.  
  37. --print总是调用tostring来格式化输出
  38. --这里我们稍作修改库定义的print
  39. function Set.tostring(a)
  40. local t={}
  41. for i in pairs(a) do
  42. t[#t+]=i
  43. end
  44. return "{"..table.concat(t,",").."}"
  45. end
  46.  
  47. --判断a集合是否是b集合的子集
  48. function Set.lessorequal(a,b)
  49. for i in pairs(a) do
  50. if not b[i] then return false end
  51. end
  52. return true
  53. end
  54.  
  55. --最后将重定向的元方法加入到元表中
  56. metatable.__add=Set.union
  57. metatable.__mul=Set.intersect
  58. metatable.__tostring=Set.tostring
  59. metatable.__le=Set.lessorequal
  60. metatable.__eq=function(a,b) return a<=b and b<=a end
  61. metatable.__lt=function(a,b) return a<=b and not (b<=a) end
  62.  
  63. s1=Set.new{,,,}
  64. s2=Set.new{,,}
  65. s3=s1+s2
  66. s4=s1*s2
  67. print(s3)
  68. print(s4)
  69. print(+,*) --新加的方法不改变表本身具有的方法,因为传入的参数不同,只会让元方法更完善
  70. s5=Set.new{,}
  71. s6=Set.new{,,}
  72. print(s5<=s6)
  73. print(s5<s6)
  74. print(s5==s6)
  75. --输出结果
  76. --{2,8,4,9,7}
  77. --{2,4}
  78. --7 12
  79. --true
  80. --true
  81. --false

2、table访问的元方法:

算数类和关系类的元方法都为各自错误情况定义了行为,他们不会改变语言的常规行为,但lua还是提供了一种可以改变table的行为。有两种可以改变table的行为:查询table以及修改table中不存在的字段。

1)、__index元方法

当访问table中不存在的字段时,得到的结果为nil。如果我们为table定义了元方法__index,那访问的结果将由该方法决定。

  1. Window={}
  2. Window.prototype={x=,y=,width=,height=}
  3. Window.mt={} --Window的元表
  4.  
  5. function Window.new(o)
  6. setmetatable(o,Window.mt)
  7. return o
  8. end
  9.  
  10. Window.mt.__index=function(table,key) return Window.prototype[key] end
  11.  
  12. w=Window.new{x=,y=}
  13. print(w.width)
  14. print(w.width1)
  15. --输出结果
  16. --
  17. --nil

2)、__newindex元方法

和__index不同的是,该元方法用于不存在键的赋值,而前者用于访问。

  1. Window={}
  2. Window.prototype={x=,y=,width=,height=}
  3. Window.mt={} --Window的元表
  4.  
  5. function Window.new(o)
  6. setmetatable(o,Window.mt)
  7. return o
  8. end
  9.  
  10. Window.mt.__index=function(table,key) return Window.prototype[key] end
  11. Window.mt.__newindex=function(table,key,value) Window.prototype[key]=value end
  12.  
  13. w=Window.new{x=,y=}
  14. w.length=
  15. print(w.width)
  16. print(w.width1)
  17. print(Window.prototype.length)
  18. --输出结果
  19. --
  20. --nil
  21. --

lua元表与元方法的更多相关文章

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

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

  2. lua——元表、元方法、继承

    [元表] 元表中的键为事件(event),称值为元方法(metamethod). 通过函数getmetatable查询不论什么值的元表,通过函数setmetatable替换表的元表. setmetat ...

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

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

  4. lua 元表与元方法示例

    -- 1.检查是否有元表local t = {1, 2}print(getmetatable(t))     -- nilprint("----------------------" ...

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

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

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

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

  7. 【游戏开发】小白学Lua——从Lua查找表元素的过程看元表、元方法

    引言 在上篇博客中,我们简单地学习了一下Lua的基本语法.其实在Lua中有一个还有一个叫元表的概念,不得不着重地探讨一下.元表在实际地开发中,也是会被极大程度地所使用到.本篇博客,就让我们从Lua查找 ...

  8. lua编程之元表与元方法

    一. 前言 lua是一种非常轻量的动态类型语言,在1993年由由Roberto Ierusalimschy.Waldemar Celes 和 Luiz Henrique de Figueiredo等人 ...

  9. Lua中的元表与元方法学习总结

    前言 元表对应的英文是metatable,元方法是metamethod.我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了"+"符号,就可以进行类的加法运算.在Lu ...

随机推荐

  1. log4jdbc 使用

    像 hibernate, mybatis 都是不打印真正执行的sql的,所以借助 log4jdbc 打印sql以及统计执行时间是非常方便的. 配置log4jdbc 有很多种方法,比如通过spring的 ...

  2. URL、URN、URI的区别?

    URL.URN.URI区别 既然Web应用程序的文件等资源是放在服务器上,而服务器是因特网(Internet)上的主机,当然必须要有个方法,告诉浏览器到哪里取得文件等资源.通常会听到有人这么说:“你要 ...

  3. Unix目录结构的来历

    作者: 阮一峰 Unix(包含Linux)的初学者,常常会很困惑,不明白目录结构的含义何在. 举例来说,根目录下面有一个子目录/bin,用于存放二进制程序.但是,/usr子目录下面还有/usr/bin ...

  4. 【Alpha版本】冲刺总结随笔

    项目预期计划 确定代码规范与编码原则. 根据原型设计,界面设计,搭建应用大致框架,完善控件,背景等的界面设计. 根据体系结构设计,完善界面跳转逻辑,确定功能模块,实现1.0版本功能. 重点完善需求说明 ...

  5. C和指针 第五章 警告总结

    1.有符号的值得右移位操作是不可移植的 2.移位操作的位数是个负数,是未定义的 3.连续赋值的各个变量的长度 不一,导致变量值截断. #include <stdio.h> int main ...

  6. Python ORM Storm 源码修改

    安装 storm : pip install storm 目标:修改 Storm 源代码以支持自动重连文件:python安装目录/site-packages/storm/database.py 在41 ...

  7. C++基础知识(4)---例外、异常处理

    对Java熟悉的朋友们都很清楚,java中的异常处理机制是非常完善的.并且java强制使用异常处理,用户必须对有可能出现异常的情况进行处理. 在C++中并没有强制用户使用异常处理,但是使用异常处理将会 ...

  8. jQuery视差滚动插件,(附原理分析,调用方法)

    演示地址:http://www.jq22.com/jquery-info1799 jquery插件,使用验证过可用. 分析源代码后总结原理:设置background样式为fixed,判断浏览器滚动距离 ...

  9. Metro下读取txt文件

    情况1:txt是Utf8格式的. 读取代码:IList<String> lines = await Windows.Storage.FileIO.ReadLinesAsync(file); ...

  10. css垂直居中 两种方法

    在前端面试的时候我们经常会被问道怎样使一个元素在页面垂直居中呢,这也是一个老生常谈的问题了. 解决的方法基本都是使用定位来实现 div{display: fixed;left: 50%;top: 50 ...