lua的元表

原创 2018年04月17日 21:23:38

接触lua一年多,是要把lua的高级特性总结一下了.先说说元表吧.

元表是什么?为什么要有元表?

学过C++的童鞋应该知道操作符重载.例如,自定义一个复数类,可以让他的两个实例相加减等等.

同理,lua的元表也可以让两个表相加减,但是他使用了更简单的语法.lua的元表是为了扩展lua的特性,使他的功能更加丰富.

要想使一个表拥有加法操作的功能,必须给他添加一种元表__add,语法如下:

setmetatable(t, {__add = function(t1, t2) return t1.a + t2.b end})

当调用tab1 + tab2时,解释器不再报错,而是会调用上面的__add函数.不要问我为什么可以这样,要想知道答案,去看lua源代码好咯.

把上面的tab1,tab2任意一个设置__add元表都可以. tab1+tab2时会调用__add. tab1传给参数t1, tab2传给参数t2.

除了加法,还可以重定义哪些隐藏的操作.

一般的运算和逻辑操作都可以重定义.有二元的,也有一元的.

下面的表包括了常见的运算符.

模式描述
__add对应的运算符 '+'.
__sub对应的运算符 '-'.
__mul对应的运算符 '*'.
__div对应的运算符 '/'.
__mod对应的运算符 '%'.
__unm对应的运算符 '-'.
__concat对应的运算符 '..'.
__eq对应的运算符 '=='.
__lt对应的运算符 '<'.
__le对应的运算符 '<='.

对于二元的__eq,再举个例子:

setmetatable(t, {__eq = function(a, b) return #a == #b end})

一元的__unm:

setmetatable(t, {__eq = function(a) local r = {} r[1] = -a[1] return r end})

t = {1}

调用ft = -t,则ft[1] = -1

忘了说了setmetatable返回要操作的表本身,所有我们一般这么调用:

local t = setmetatable({}, ...),临时表返回给一个变量.

注意,每种操作的函数返回值会不一样,比较操作只能返回bool,求长度只能返回integer,取反操作只能返回一个新的表.

除了扩展表的操作,还有什么秘密武器呢.就是下面要说的重点了,所有lua的高级特性,诸如模拟面向对象的继承,保护表元素等都离不开他.

先说说__index,如果这样设置:

t = {name = 'shonm'}
t_extra = {extra = 123}
setmetatable(t, {__index = t_extra })

t.name    --他的值为 'shonm'

t.extra     --在t表里我们没有定义extra字段,但是现在却可以访问到了,值为123,就是因为设置了元表__index

在查找t的extra字段时,没有找到,那么就会去他的元表的__index字段里查找,看是否有字段为extra.

如果就是很犟,非要知道,初始的表t里面有没有extra这个字段怎么办?还是有办法滴.调用rawget(t, 'extra')就好.

不要小看了这个过程,他的威力很强大,可以实现面向对象的特性了.例如下面的一段代码,就是子类访问父类的字段:

father = {
    house = 1
}

son = {
    car = 1
}
father.__index = father
setmetatable(son, father)
print(son.house)  --1

还有构造新对象:

local Obj = {}
function Obj:new (obj)  
    obj = obj or {}  
    setmetatable(obj, self)  
    self.__index = self  
    return obj  
end  
local o = Obj:new({})   --o相当于Obj的一个实例,可以调用Obj的所有方法了

是不是很奇特!

元表__index相当于对数据访问的扩展,现在问题来了,那你能不能做数据保护呢?即定义好表的数据之后,不能往里面添加字段.元表__newindex就可以做到了.

简单的来说,__newindex就是,当你要写表的数据,即向表添加新字段时,他会来接管.如果__newindex是函数,为了保护表,可以在函数中抛出错误. 例如:

local days = {"星期一", "星期二", "星期三"}
setmetatable(days, {__newindex = function()
            error("do not modify me!!!");
        end })
        
print(days[3])     --可以访问
days[4] = 'Tues'   --do not modify me!!!

如果__newindex是一个表,那么这个值会赋给那个表.例如:

local ta = {}
local t = {}
setmetatable(t, {__newindex = ta })
t.money = 123
print(t.money, ta.money)

结果为nil, 123

给t.money赋值时会触发元表__newindex.

刚才数据保护的那段代码不通用,能否用一个函数实现数据保护.

__index和__newindex,结合就可以:

local function readOnly(t)
    local newT = {};
    local mt = {
        __index = t,
        __newindex = function()
            error("do not modify me");
        end
    }
    setmetatable(newT, mt);
    return newT;
end
local t = {"星期一", "星期二", "星期三"}
local days = readOnly(t);

days[4] = 'Tues'   --do not modify me!!!

上面的代码还有个漏洞就是,如果调用rawset(days, ...)那就没有办法了.

看了一下午的资料总结的,写文章确实耗时间,都9点多了,呵呵.


参考资料:

http://www.benmutou.com/archives/1779










用TAPI 3.0 建立呼叫中心

用TAPI 3.0 建立呼叫中心微软 2000/09/09  在以IP技术为基础的局域网、广域网以及互联网上的IP电话能够将语音、数据和视频集成在一起,这是一项正在逐步发展并走向成熟的技术。IP电话使...
  • tchaikov
  • tchaikov
  • 2000-12-20 16:59:00
  • 1505

lua学习笔记16:table元表详解

一 table本质 Lua中table本质实际上是个类似HashMap东西。 其元素是很多的Key-Value对,类似iOS中的字典NSDictionary。 如果尝试访问了一个表中并不存在的元...
  • xufeng0991
  • xufeng0991
  • 2015-02-07 20:17:43
  • 2561

lua元表理解

在lua中任何变量都有一个元表(我相信每个字符串元表都是string相关,所以可以使用string:length()),元表中特殊的值有特殊的含义,比如__index,__call,__add等等。 ...
  • zbffff
  • zbffff
  • 2015-08-23 22:13:22
  • 6361

lua 的元表和元表的__index字段

众所周知,lua的继承是通过元表的__index字段来实现的,比如child类要继承自parent类,就需要把child的元表设为parent,并且要把child的元表(此时是parent)的__in...
  • sibaison
  • sibaison
  • 2017-02-26 14:59:03
  • 588

lua 元表 __index 继承的实现

Lua的表本质其实是个类似HashMap的东西,其元素是很多的Key-Value对,如果尝试访问了一个表中并不存在的元素时,就会触发Lua的一套查找机制,也是凭借这个机制,才能够实现“面向对象”的。 ...
  • xiaogou56a
  • xiaogou56a
  • 2015-02-27 15:37:30
  • 768

详解Lua中的元表概念

Lua中的元表概念 点击打开链接
  • u010616114
  • u010616114
  • 2016-07-15 14:42:32
  • 1014

Lua元表与元方法详解(转)

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

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

【元表】 元表中的键为事件(event),称值为元方法(metamethod)。 通过函数getmetatable查询任何值的元表,通过函数setmetatable替换表的元表。 set...
  • adfansong
  • adfansong
  • 2015-08-17 20:39:48
  • 1863

LUA元表和类的简单例子

学习lua有一段时间了,今天终于学会了怎么使用元表,还有用lua表模拟类,综合实例讲解,用lua元表模拟C++模板和类...
  • zhouxicai
  • zhouxicai
  • 2013-11-25 17:16:07
  • 2189

Lua下通过元表模拟OOP编程,继承多态

Lua本身是没有以明确的定义来支持OOP编程的,但是我们却可以通过Lua本身提供的一些特性来间接实现简单的面向对象的编程。...
  • yue7603835
  • yue7603835
  • 2014-12-09 10:16:01
  • 3761
收藏助手
不良信息举报
您举报文章:lua的元表
举报原因:
原因补充:

(最多只允许输入30个字)