lua学习(二)元表

本文大量参考OpenResty最佳实践以及lua元表详解

-->>>>>>>>>>>>>>>> 元表
-- 元表是用来定义table或userdata操作方式的表,可以用来实现面向对象
-- 元表的设置
-- 定义元表
local t1 = {1,2,3}
local t2 = {2}
local mt = {}

-- 定义元表mt.__add元方法
mt.__add = function(t1,t2)
    local temp = {}
    for _,v in pairs(t1) do
        table.insert(temp,v)
    end
    for _,v in pairs(t2) do
        table.insert(temp,v)
    end

    return temp
end



-- 设置t1的元表为mt
setmetatable(t1,mt)
local t3 = t1+t2 --> 实际上t3 = t2+t1也是可以的。编译器会查看t1是否有元表,并查看t1的元表是否有__add元方法,若有则调用;查看t2是否有元表,并查看t2的元表是否有__add元方法,若有则调用
-- 输出t3
local st = "{"
for _,v in pairs(t3) do
    st = st..v..", "
end
st = st.."}"
print(st)
--结果
--{1, 2, 3, 2, }

-- 实际上还可以对__add元方法进行重载,重载的第一个参数时self,但是这里的重载导致之后的__call方法如果不重新使用setmetatable(t1,mt)会报错,如果不重载就不会,
local union = function(self,another)
    local temp = {}
    for _,v in pairs(another) do
        table.insert(temp,v)
    end
    for _,v in pairs(self) do
        table.insert(temp,v)
    end
    return temp
end

setmetatable(t1, {__add = union})
local t4 = t1+t2
local st = "{"
for _,v in pairs(t4) do
    st = st..v..", "
end
st = st.."}"
print(st)
--结果:
--{2, 1, 2, 3, }

-- 定义__call可以让table当做一个函数来使用
mt.__call = function(mytable,...)
    -- 输出所有的参数
    for _,v in  ipairs{...} do
        print(v)
    end
end

setmetatable(t1,mt)
t1(1,2,3)
--结果
--1
--2
--3

-- 修改__tostring可以修改table转化为字符串的行为
print(t1)
mt.__tostring = function(t)
    local s = "{{"
    for i,v in ipairs(t) do
        if i > 1 then
            s = s..","
        end
        s = s..v
    end
    s = s.."}}"
    return s
end
print(t1)
--结果:
--table: 0x000cbc80
--{{1,2,3}}

-- 当调用到table一个不存在的索引是,会使用到元表的__index元方法,和之前方法不一样的是,__index既可以是函数也可以是table
print(t1.key)

mt.__index = function(t,key)
    return "it is "..key
end

print(t1.key)

mt.__index = {key = "it is a beautiful key"}
print(t1.key)
print(t1.key2)
--结果:
--nil
--it is key
--it is a beautiful key
--nil

--当为table中一个不存在的索引赋值时,会调用元表中的__newindex元方法
mt.__newindex = function(t,index,value)
    print("index is "..index)
    print("value is "..value)
end

t1 = {key = "it is a hello key"}
setmetatable(t1,mt) --> 此时的t1已经属于新创建的t1,因此需要重新设置元表
print(t1.key)
t1.newKey = 10 --> 实际中表的newKey索引值还是为空,上面只是调用了元表的__newIndex方法,输出了参数信息
print(t1.newKey)
--结果:
--it is a hello key
--index is newKey
--value is 10
--nil

--在__neweindex作为一个table时,为不存在的索引赋值会导致该索引和赋值被赋到__newindex所指向的表中,不会对原来的表进行修改
local newTable = {}
mt.__newindex = newTable
t1 = {}
setmetatable(t1,mt)
print(t1.newKey,newTable.newKey)
t1.newKey = "it is a hello kitty"
print(t1.newKey,newTable.newKey)
--结果:
--nil	nil
--nil	it is a hello kitty

-- rawget以及rawset可以直接获取表中索引的实际值,并进行赋值,而不受元方法影响
mt.__index = {key = "it is hhkey"}
t1 = {}
setmetatable(t1,mt)
print(t1.key)
--通过rawget可以直接获取t中的key索引,不受__index元方法的影响
print(rawget(t1,"key"))
--结果:
--it is hhkey
--nil

--rawset可以直接为表中索引赋值,而不通过元表的__newindex元方法
local newTable = {}
mt.__newindex = newTable
t1 = {}
setmetatable(t1,mt)
print(t1.newKey,newTable.newKey)
rawset(t1,"newKey","it is 233key")
print(t1.newKey,newTable.newKey)
--结果:
--nil	nil
--it is 233key	nil

-- 如果想保护对象对其使用者既看不到也不能修改metatables,
-- 我们可以对metatable设置__metatable的值,getmetatable将会返回这个值,而调用setmetatable将会出错
local t1 = setmetatable({},{__metatable="You cannnot access here"})
print(getmetatable(t1))
-- setmetatable(t1,{}) -- 此时该语句会引发编译器报错
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值