1. Lua中每个值都可具有元表。 元表是普通的Lua表,定义了原始值在某些特定操作下的行为。你可通过在值的原表中设置特定的字段来改变作用于该值的操作的某些行为特征。例如,当数字值作为加法的操作数时,Lua检查其元表中的"__add"字段是否有个函数。如果有,Lua调用它执行加法。
  2.  
  3. 我们称元表中的键为事件(event),称值为元方法(metamethod)。前述例子中的事件是"add",元方法是执行加法的函数。
  4.  
  5. 可通过函数getmetatable查询任何值的元表。
  6.  
  7. 可通过函数setmetatable替换表的元表。不能从Lua中改变其他类型的元表(除了使用调试库);必须使用C API才能做到。
  8.  
  9. 表和完整的用户数据具有独立的元表(尽管多个表和用户数据可共享元表);每种其他类型的所有值共享一个元表。所以,所有数字共享一个元表,字符串也是,等等。
  10.  
  11. 元表可以控制对象的数学运算、顺序比较、连接、取长、和索引操作的行为。元表也能定义用户数据被垃圾收集时调用的函数。Lua给这些操作的每一个都关联了称为事件的特定键。当Lua对某值执行其中一个操作时,检查该值是否含有元表以及相应的事件。如果有,与该键关联的值(元方法)控制Lua如何完成操作。
  12.  
  13. 元表控制后面列举的操作。每个操作由相应的名字标识。每个操作的键是由其名字前缀两个下划线“__”的字符串;例如,操作“加(add)”的键是字符串"__add"。这些操作的语义通过一个Lua函数描述解释器如何执行操作作了更好的说明。
  14.  
  15. 下面显示的Lua代码只是说明性的;真实的行为被硬编码到解释器中,并且比这里的模拟更加高效。这些描述中的所有函数(rawgettonumber等等。)在§5.1中描述。特别一提,要获取给定对象的元方法,我们使用表达式
  16.  
  17. metatable(obj)[event]
  18.  
  19. 它应被解读为
  20.  
  21. rawget(getmetatable(obj) or {}, event)
  22.  
  23. 就是说,访问一个元方法不会调用其他元方法,而且访问没有元表的对象不会失败(只是结果为nil)。
  24.  
  25. "add": + 操作。
  26. 下面的getbinhandler函数定义Lua如何选择二元操作的处理程序。首先尝试第一操作数,如果它的类型没有定义该操作的处理程序,则尝试第二操作数。
  27.  
  28. function getbinhandler (op1, op2, event)
  29. return metatable(op1)[event] or metatable(op2)[event]
  30. end
  31.  
  32. 通过应用该函数,op1 + op2的行为是
  33.  
  34. function add_event (op1, op2)
  35. local o1, o2 = tonumber(op1), tonumber(op2)
  36. if o1 and o2 then -- 两操作数都是数字
  37. return o1 + o2 -- ‘+’此处是‘add’的原语
  38. else -- 至少一个操作数不是数字
  39. local h = getbinhandler(op1, op2, "__add")
  40. if h then -- 用两个操作数调用处理程序
  41. return (h(op1, op2))
  42. else -- 没有可用的处理程序:缺省行为
  43. error(...)
  44. end
  45. end
  46. end
  47.  
  48. "sub": - 操作。 行为类似于“add”操作。
  49. "mul": * 操作。 行为类似于“add”操作。
  50. "div": / 操作。 行为类似于“add”操作。
  51. "mod": % 操作。 行为类似于“add”操作。以o1 - floor(o1/o2)*o2为操作原语。
  52. "pow": ^ (取幂)操作。 行为类似于“add”操作,以函数pow(来自C数学库)为操作原语。
  53. "unm": 一元-操作。
  54. function unm_event (op)
  55. local o = tonumber(op)
  56. if o then -- 操作数是数字?
  57. return -o -- ‘-’此处是‘unm’的原语
  58. else -- 操作数不是数字
  59. -- 尝试由操作数取得处理程序。
  60. local h = metatable(op).__unm
  61. if h then-- 用操作数调用处理程序
  62. return (h(op))
  63. else -- 没有可用的处理程序:缺省行为
  64. error(...)
  65. end
  66. end
  67. end
  68.  
  69. "concat": .. (连接)操作。
  70. function concat_event (op1, op2)
  71. if (type(op1) == "string" or type(op1) == "number") and
  72. (type(op2) == "string" or type(op2) == "number") then
  73. return op1 .. op2 -- 字符串连接原语
  74. else
  75. local h = getbinhandler(op1, op2, "__concat")
  76. if h then
  77. return (h(op1, op2))
  78. else
  79. error(...)
  80. end
  81. end
  82. end
  83.  
  84. "len": # 操作。
  85. function len_event (op)
  86. if type(op) == "string" then
  87. return strlen(op) -- 取字符串长度原语
  88. elseif type(op) == "table" then
  89. return #op -- 取表长度原语
  90. else
  91. local h = metatable(op).__len
  92. if h then -- 用操作数调用处理程序
  93. return (h(op))
  94. else -- 没有可用的处理程序:缺省行为
  95. error(...)
  96. end
  97. end
  98. end
  99.  
  100. "eq": == 操作。 函数getcomphandler定义Lua如何选择比较操作符的元方法。只有待比较的两个对象类型和选定操作对应的元方法都相同,才会选择该元方法。
  101. function getcomphandler (op1, op2, event)
  102. if type(op1) ~= type(op2) then return nil end
  103. local mm1 = metatable(op1)[event]
  104. local mm2 = metatable(op2)[event]
  105. if mm1 == mm2 then
  106. return mm1
  107. else
  108. return nil
  109. end
  110. end
  111. "eq"事件定义如下:
  112. function eq_event (op1, op2)
  113. if type(op1) ~= type(op2) then -- 类型不同?
  114. return false -- 对象不同
  115. end
  116. if op1 == op2 then -- 相等原语?
  117. return true -- 对象相同
  118. end -- 尝试元方法
  119. local h = getcomphandler(op1, op2, "__eq")
  120. if h then
  121. return (h(op1, op2))
  122. else
  123. return false
  124. end
  125. end
  126. a ~= b等价于not (a == b)。
  127.  
  128. "lt": < 操作。
  129. function lt_event (op1, op2)
  130. if type(op1) == "number" and type(op2) == "number" then
  131. return op1 < op2 -- 数字比较
  132. elseif type(op1) == "string" and type(op2) == "string" then
  133. return op1 < op2 -- 词典顺序比较
  134. else
  135. local h = getcomphandler(op1, op2, "__lt")
  136. if h then
  137. return (h(op1, op2))
  138. else
  139. error(...);
  140. end
  141. end
  142. end
  143. a > b等价于b < a
  144.  
  145. "le": <= 操作。
  146. function le_event (op1, op2)
  147. if type(op1) == "number" and type(op2) == "number" then
  148. return op1 <= op2 -- 数字比较
  149. elseif type(op1) == "string" and type(op2) == "string" then
  150. return op1 <= op2 -- 词典顺序比较
  151. else
  152. local h = getcomphandler(op1, op2, "__le")
  153. if h then
  154. return (h(op1, op2))
  155. else
  156. h = getcomphandler(op1, op2, "__lt")
  157. if h then
  158. return not h(op2, op1)
  159. else
  160. error(...);
  161. end
  162. end
  163. end
  164. end
  165. a >= b等价于 b <= a。注意,假定a <= b等价于not (b < a),那么当没有“le”元方法时,Lua尝试“lt”。
  166.  
  167. "index": 索引访问table[key]。
  168. function gettable_event (table, key)
  169. local h
  170. if type(table) == "table" then
  171. local v = rawget(table, key)
  172. if v ~= nil then
  173. return v
  174. end
  175. h = metatable(table).__index
  176. if h == nil then
  177. return nil
  178. end
  179. else
  180. h = metatable(table).__index
  181. if h == nil then
  182. error(...);
  183. end
  184. end
  185. if type(h) == "function" then
  186. return (h(table, key)) -- 调用处理程序
  187. else
  188. return h[key] -- 对它重复上述操作
  189. end
  190. end
  191.  
  192. "newindex": 索引赋值table[key] = value
  193. function settable_event (table, key, value)
  194. local h
  195. if type(table) == "table" then
  196. local v = rawget(table, key)
  197. if v ~= nil then
  198. rawset(table, key, value);
  199. return
  200. end
  201. h = metatable(table).__newindex
  202. if h == nil then
  203. rawset(table, key, value);
  204. return
  205. end
  206. else
  207. h = metatable(table).__newindex
  208. if h == nil then
  209. error(...);
  210. end
  211. end
  212. if type(h) == "function" then
  213. h(table, key,value) -- 调用处理程序
  214. else
  215. h[key] = value -- 对它重复上述操作
  216. end
  217. end
  218.  
  219. "call": Lua调用值时被调用。
  220. function function_event (func, ...)
  221. if type(func) == "function" then
  222. return func(...) -- 调用原语
  223. else
  224. local h = metatable(func).__call
  225. if h then
  226. return h(func, ...)
  227. else
  228. error(...)
  229. end
  230. end
  231. end

  

Lua中的元表和元方法的更多相关文章

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

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

  2. Lua中的元表与元方法

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

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

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

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

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

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

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

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

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

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

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

  8. Lua中的元表(metatable)、元方法(metamethod)详解

    在第一次看见这两样东西的时候,可能会觉得它很深奥,但其实很好理解,虽然实际上它可能真的很深奥.(小若:停!滚粗.) 1.知道为什么1 + 1 = 2吗? 为什么在Lua中,1+1会等于2呢?(小若:难 ...

  9. lua元表与元方法

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

随机推荐

  1. layer弹出层的关闭问题

    就是在执行添加或修改的时候,需要将数据提交到后台进行处理,这时候添加成功之后最理想的状态是关闭弹出层并且刷新列表的数据信息,之前一直想实现这样,可一直没有成功,今天决定好好弄一弄,在仔细看过layer ...

  2. 洛谷P2408 不同字串个数 [后缀数组]

    题目传送门 不同字串个数 题目背景 因为NOI被虐傻了,蒟蒻的YJQ准备来学习一下字符串,于是它碰到了这样一道题: 题目描述 给你一个长为N的字符串,求不同的子串的个数 我们定义两个子串不同,当且仅当 ...

  3. eclipse的一些部署

    1. Eclipse导入一个项目Package Exporer-------右键------import------General------Existing Project into Workspa ...

  4. Cookie的用法

    string strCookie=""; //创建一个名为user HttpCookie userCookie=new HttpCookie("user"); ...

  5. 常用的JVM配置参数

    一.Trace 跟踪参数 在Eclipse中,如何打开GC的监控日志 选择菜单栏Run -> Run Configurations -> Java Application -> 选择 ...

  6. 【BZOJ 3727】 3727: PA2014 Final Zadanie (递推)

    3727: PA2014 Final Zadanie Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 279  Solved: 121 Descript ...

  7. codevs1081 线段树练习 2<区间修改>

    1081 线段树练习 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master   题目描述 Description 给你N个数,有两种操作 1:给区间[a,b]的所有 ...

  8. [CODECHEF]EASYEX

    题意:有一个$k$面的骰子,上面的数字为$1\cdots k$,现在要丢$n$次骰子,设$n$次中有$a_i$次扔到数字$i$,给定$l,f$,求$\prod\limits_{i=1}^la_i^f$ ...

  9. 【树形DP】BZOJ1596-[Usaco2008 Jan]电话网络

    [题目大意] 在一棵有n个节点的树上建信号塔,每个节点的信号塔可以覆盖当前节点极其相连的节点.问要覆盖所有节点,至少需要多少座信号塔? [思路] 经典的树形DP,直接复制一下. f[i][0]:以i为 ...

  10. 用ExifInterface读取经纬度的时候遇到的一个问题

    如果读取图片经纬度,使用 String latValue = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE); String ln ...