理解Lua中“元表和元方法“

小细节 :一般运行lua程序是 lua ./文件名
但可以在这个lua文件开头加上这句话,则可以直接 ./文件名 就可以执行对应文件
#!/usr/local/bin/lua

假设文件名是hello.lua , 则可以直接 ./hello.lua 执行这个文件

这个路径有可能跟我不一样,要看lua在哪里

– pairs 和 ipairs的区别
– ipairs遍历table时,键值从1递增,当键值中断(如[1]过了就是[3])或遇到nil时退出
– pairs 会遍历表中所有键值对,且元素是根据哈希算法来排序的,所以打印出来的顺序是乱的

简单说一下什么是元表和元方法

test = {}
test.hello = function()
	print("hha")
end

元表可以绑定在一个普通的表或者一个userdata上, 比如现在有一个普通表test, 当我们正常调用test.hello的时候,可以正常的调用这个函数,但如果我们调用test.world, 我们可以发现,test表中并没有world的对应函数,于是就会去与test表绑定的元表中寻找world函数。

我上边说的这种情况(找不到world函数),会去test的元表中寻找__index 字段,当然只是上边这种情况会去寻找__index字段对应的处理方式, 还有其他处理方式,后边会一一介绍,__tostring, __call方法等。

这里我们假设Vector 是一个元表
Vector = {}
Vector.__index = Vector
– 这步必须要,因为Vector是一个元表,当这个元表对应的普通表找不到对应的函数的时候
– 就会去这个元表(Vector)的__index中查找,这样设置后,__index中就包含元表的所有函数,即整个元表
– 需要理解一点 __index只是一个元方法,当出现在普通表中找不到函数的情况
– 就会去找这个普通表对应的元表的__index方法,来进一步寻找,就和__tostring, __call 一样
– 元方法只是普通表遇到特定情况时的解决方案,所以这种情况下需要设置 元表.__index = 元表

重点:只是__index 字段是这样设置,__tostring,__call就不是这样设置的,所以需要清楚明白的一点就是,Vector.__index = Vector这样只是为了设置__index元方法这一种元方法,还有很多其他的元方法。

学习建议:跟着把下边的代码都敲一遍,并且每一个案例都成功运行,就能学懂lua中的元表和元方法。

所谓的元表和普通表一样,都是table结果,是否作为元表,取决于你自己的操作

lua中的结构中只有table和userdata可以独立的设置元表

__index元方法

这是metatable元表最常用的键了。

当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的 __index 键。如果 __index 包含一个表格,Lua会在表格中查找相应的键。

t = {}  --作为普通表		
mt = {}  --作为元表
setmetatable(t,mt);-- 会将第二个表设置为第一个参数的表的原表
getmetatable(t);

t = setmetatable({[2] = 3}, {
    __index = function(t,key)
        if key == "foo" then
            return 0
        else
            return table[key]
        end
    end
});

other = {foo = 3}
-- t = setmetatable({}, {__index = other})
print(t.foo)  -- 0
print(t.bar)  -- nil
print(t[2])   --3

__newindex 元方法

类似 __index , __newindex 的值为函数或table,用于按键赋值的情况。
当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法

other = {}
-- setmetatable 会将第二个表设置为第一个参数的表的原表
-- 并且会将第一个参数的表返回
t = setmetatable({}, {__newindex = other})
t.foo = 3

t = setmetatable({}, {
    __newindex = function(t, key, value)
        if type(value) == "number" then
        rawset(t, key, value * value)
    else
        rawset(t, key, value)
    end
end
})

t.foo = "foo"
t.bar = 4
t.la = 10
print(t.foo)
print(t.bar)
print(t.la)

__mul 元方法 (乘法)

t = setmetatable({1,2,3}, {
    __mul = function(t, other)
    new = {}
    
    for i = 1, other do
        for _, v in ipairs(t) do 
        table.insert(new, v) 
        end
    end

    return new
end
})

t = t * 2 -- 将上边的1,2,3  变成了1,2,3,1,2,3
for v,k in pairs(t) do
    print(v,k) --这种方式会把key和value一起打印出来   
end

__call 的原方法

使得你可以像调用函数一样调用table:
也就是当table名字作为函数名字的时候会被调用
下边可以观察到,本来t是一个table,却当作函数来使用

t = setmetatable({}, {
    __call = function(t, a, b, c, whatever)
    return (a +b +c) * whatever
end
})
print(t(1,2,3,4))

__tostring的元方法

– 它可以将一个table转换成字符串,常和print配合使用
– 如果不使用__tostring元方法,默认的print(表名) 会打印处一串地址

t = setmetatable({1, 2 ,3}, {
    __tostring = function(t)
        sum = 0
        for _, v in pairs(t) do 
        sum = sum + v 
        end
        return "Sum:"..sum
end
})

print(t)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值