[Lua] metatable学习

如果说table这种数据结构是Lua的利剑,那么metatable就是Lua的强盾了。metatable可以辅助table完成许多难以实现的功能。

一.什么是metatable

metatable根据其英文翻译就是元表的意思。metatable允许我们改变table的行为,每个行为关联了对应的元方法。
其中就有两个很重要的函数来处理元表:

  • setmetatable(table,metatable):对指定table 设置元表(metatable),如果元表中含有键__metatable , setmetatable则会失败。记得 返回值是table
  • getmetatable(table):返回对象的元表(metatable)。

二.metatable的运用

设置元表

mytable = {}                       -- 普通表
mymetatable = {}                   -- 元表
setmetatable(mytable,mymetatable)  -- 把mymetatable 设为mytable 的元表

以上代码也可以直接写成一行:

mytable = setmetable({} , {})

返回对象元表:

getmetatable(mytable)               -- 返回mymetatable

三.元方法

metatable作为一个容器,其中的元方法才是真正发挥真正效果的法宝。

1.__index 元方法

这是metatable最常用的键。
当你通过键来访问table的时候,如果这个键没有对应的值,Lua会去判断table是否有元表,如果没有元表就返回nil。如果有元表,则会去调用__index方法,如果__index是一个table,则会去table中查找该键所对应的值。下面具体演示一下

-- 继续承接上面的代码
mymetatable.__index={ foo = 3 }    -- 设置元方法__index为table
print(mytable.foo)
-- 输出 
-- 3

等同于下面这段

mytable = setmetatable( {} , { __index = { foo = 3} } )  -- 第一个{} 返回给mytable 后面定义了metatable中的__index元方法
print(mytable.foo)
-- 输出 
-- 3

当然__index也可以当做函数处理,有着固定的格式(建议)

__index = function(table,key) -- table就是你的普通表 key就是普通表传来的键
-- 这里等于给__index传了一个匿名函数

举个例子:

mytable     = { key1 = "C#" }
mymetatable = { __index =   function(table,key)
								if(key == "key2") then
									return "Java"
								else
									return "Lua"
								end
							 end}
setmetatable(mytable , mymetatable)
print(mytable.key1 , mytable.key2 , mytable.key3)
-- 输出 
-- C# Java Lua

上面的代码稍微解释一下。
mytable.key1因为是mytable中就有的键,所以直接找到相应的值为C#。
mytable.key2因为mytable中没有搜索到该键,所以Lua就去找mytable的元表mymetatable中调用__index元方法看是否能找到,function中table传入的就是"mytable",key参数传入的就是搜索的"key2",所以if语句判断成功返回Java。
最后mytable.key3根据上面的推理,由else语句返回Lua。

  • Lua并不是一个面向对象的语言,但是利用__index就可以实现简易的继承功能
local test = {}

function test : new ()
    self.__index = self    
    return setmetatable({} , self);
end

function test : say ()
    print("你好")
end

local t1 = test:new();
t1.say();

function t1 : say()
    print("Hello")
end

local t2 = t1:new();
t2.say();

-- 输出
-- 你好
-- Hello
2.__newindex 元方法

__newindex元方法用来对表更新,__index则用来对表访问。
当你给表的一个缺少的索引赋值,编译器就会查找__newindex元方法:如果存在则调用这个函数而不进行赋值操作。

mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)
-- 输出 
-- value1
-- nil    新值2
-- 新值1  nil

以上实例中表设置了元方法 __newindex,在对新索引键(newkey)赋值时(mytable.newkey = “新值2”),会调用元方法,而不进行赋值。而如果对已存在的索引键(key1),则会进行赋值,而不调用元方法 __newindex。

3.__call 元方法

__call元方法允许给table调用一个值时调用。

mytable = setmetatable({} , {
    __call = function (mytable,key)
        if(key == 1) then
            print("111")
        else
            print("222")
        end                                    
    end
})
mytable(1)
mytable(2)
-- 输出
-- 111
-- 222

当给mytable传入参数1时,这里会调用其元表中的__call元方法。元方法中定义的table就是代指普通表mytable,而key指的就是调用table时传入的参数,这里就是1。后面的逻辑就能搞懂了。

4.__tostring 元方法

__tostring 元方法用于修改表的输出行为。

mytable = setmetatable( {10 , 20 , 30 } , {
    __tostring = function (table)
        sum = 0
        for _ , v in ipairs(table) do
            sum = sum + v
        end
        return "表中所有元素之和"..sum
    end
})
print(mytable)
-- 输出
-- 表中所有元素之和60

更多的元方法

模式描述
__add对应的运算符 ‘+’
__sub对应的运算符 ‘-’
__mul对应的运算符 ‘*’
__div对应的运算符 ‘/’
__mod对应的运算符 ‘%’
__unm对应的运算符 ‘-’
__concat对应的运算符’…’
__eq对应的运算符’==’
__lt对应的运算符’<’
__le对应的运算符’<=’
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值