博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lua中的元表与元方法
阅读量:6976 次
发布时间:2019-06-27

本文共 2474 字,大约阅读时间需要 8 分钟。

前言

元表对应的英文是metatable,元方法是metamethod。我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了“+”符号,就可以进行类的加法运算。在Lua中也有这个道理,两个table类型的变量,你是无法直接进行“+”操作的,如果你定义了一个指定的函数,就可以进行了。那这篇博文就是主要讲的如何定义这个指定的函数,这个指定的函数是什么?希望对学习Lua的朋友有帮助。

Lua是怎么做的?

通常,Lua中的每个值都有一套预定义的操作集合,比如数字是可以相加的,字符串是可以连接的,但是对于两个table类型,则不能直接进行“+”操作。这需要我们进行一些操作。在Lua中有一个元表,也就是上面说的metatable,我们可以通过元表来修改一个值得行为,使其在面对一个非预定义的操作时执行一个指定的操作。比如,现在有两个table类型的变量a和b,我们可以通过metatable定义如何计算表达式a+b,具体的在Lua中是按照以下步骤进行的:

  1. 先判断a和b两者之一是否有元表;
  2. 检查该元表中是否有一个叫__add的字段;
  3. 如果找到了该字段,就调用该字段对应的值,这个值对应的是一个metamethod;(Lua中方法是可以放在一个字段中的,还记得???忘了点)
  4. 调用__add对应的metamethod计算a和b的值。

上述四个步骤就是计算table类型变量a+b的过程。在Lua中,每个值都有一个元表,table和userdata类型的每个变量都可以有各自独立的元表,而其他类型的值则共享其类型所属的单一元表。

告别metatable小白

现在就说说最基本的metatable内容。Lua在创建新的table时不会创建元表,比如以下代码就可以演示:

local t = { 1, 2} print(getmetatable(t)) -- nil

我们是使用getmetatable来获取一个table或userdata类型变量的元表,当创建新的table变量时,使用getmetatable去获得元表,将返回nil;同理,我们也可以使用setmetatable去设置一个table或userdata类型变量的元表,例如以下代码:

local t = {} print(getmetatable(t)) -->nil local t1 = {} setmetatable(t, t1) assert(getmetatable(t) == t1)

任何table都可以作为任何值得元表,而一组相关的table有可以共享一个通用的元表,此元表描述了它们共同的行为。一个table甚至可以作为它自己的元表,用于描述其特有的行为。总之,任何搭配形式都是合法的。

在Lua代码中,只能设置table的元表。若要设置其它类型的值得元表,则必须通过C代码来完成。还存在一个特例,对于字符串,标准的字符串程序库为所有的字符串都设置了一个元表,而其它类型在默认情况下都没有元表。查看两句代码的打印值,就可以看出来:

print(getmetatable("Hello World")) print(getmetatable(10))

在table中,我可以重新定义的元方法有以下几个:

__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 --保护元表

接下来就介绍介绍如果去重新定义这些方法。

算术类的元方法

现在我使用完整的实例代码来详细的说明算术类元方法的使用。我准备定义一些对集合的操作方法,所有的方法都放入Set这个table中,至于为什么table中可以存放函数,可以参考这篇文章。下面的代码是我模拟的一个集合的操作:

Set = {} local mt = {} -- 集合的元表 -- 根据参数列表中的值创建一个新的集合 function Set.new(l) local set = {} setmetatable(set, mt) for _, v in pairs(l) do set[v] = true end return set end -- 并集操作 function Set.union(a, b) local retSet = Set.new{} -- 此处相当于Set.new({}) for v in pairs(a) do retSet[v] = true end for v in pairs(b) do retSet[v] = true end return retSet end -- 交集操作 function Set.intersection(a, b) local retSet = Set.new{} for v in pairs(a) do retSet[v] = b[v] end return retSet end -- 打印集合的操作 function Set.toString(set) local tb = {} for e in pairs(set) do tb[#tb + 1] = e end return "{" .. table.concat(tb, ", ") ..

转载于:https://www.cnblogs.com/liuqing0328/p/5085188.html

你可能感兴趣的文章
docker network基础
查看>>
Android蓝牙栈bluez使用方法
查看>>
软件安装
查看>>
go for select
查看>>
关于DOM的一些基础问题
查看>>
为EasyUI 的Tab 标签添加右键菜单
查看>>
JavaScript中清空数组的三种方式
查看>>
http://jqweui.com/
查看>>
C#中反射的使用(How to use reflect in CSharp)(2)
查看>>
maven扫盲
查看>>
FPGA笔试必会知识点2—FPGA器件
查看>>
github使用技巧
查看>>
js基本类型存放和对象存放的区别(对象遍历)
查看>>
转载 数据库设计E-R图
查看>>
利用Pandas和matplotlib分析我爱我家房租区间频率
查看>>
动态DP之全局平衡二叉树
查看>>
Scrapy下xpath基本的使用方法
查看>>
leetcode: Path Sum II 迭代法
查看>>
地域划分 编程题
查看>>
如何脱离eclipse前端开发
查看>>