Lua 元表(Metatable)——从入门到放弃

Lua 元表(Metatable)

在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作。 因此 Lua
提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。
例如,使用元表我们可以定义Lua如何计算两个table的相加操作a+b。

设置元表和返回元表
setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
getmetatable(table): 返回对象的元表(metatable)。
例:
设置元表

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

或者

mytable = setmetatable({},{})

返回对象元表

getmetatable(mytable)                 -- 返回mymetatable

元方法
__index 元方法
ps:这里有个坑,_index前面是两条下划线。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表,Lua会在表中查找相应的键。
例1:

> other = { foo = 3 } 
> t = setmetatable({}, { __index = other }) 
> t.foo
3
> t.bar
nil

例2:

mytable = setmetatable({key1 = "value1"}, {
  __index = function(mytable, key)
    if key == "key2" then
      return "metatablevalue"
    else
      return nil
    end
  end
})
print(mytable.key1,mytable.key2)

结果:

value1    metatablevalue

解释:
mytable 表赋值为 {key1 = “value1”};mytable 设置了元表,元方法为 __index;元方法 __index中设置key2=metatablevalue。
在mytable表中查找 key1,找到则返回该元素。
在mytable表中查找 key2,找不到该元素,继续查找元方法的 __index键值,返回_index函数。因为传入的是key2所以返回metatablevalue。
ps:即使将A的元表设置为B,而且B中也确实有这个成员,返回结果仍然会是nil,原因就是B的__index元方法没有赋值。
例子:

husband = {
	car = 1
}
you = {
	beautiful = 1
}
setmetatable(you, husband)
print(you.car)

结果为nil

husband = {
	car = 1
}
husband.__index = husband--把husband的__index指向自己
you = {
	beautiful = 1
}
setmetatable(you, husband)
print(you.car)

结果为1

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

mymetatable = {}
mytable =setmetatable({k1="v0"},{__newindex
例:
mymetatable = {}
mytable =setmetatable({k1="v0"},{__newindex = mymetatable})

print(mytable.k1)

mytable.newk="newv2"
print(mytable.newk,mymetatable.newk)

mytable.k1 = "newv1"
print(mytable.k1,mymetatable.k1)

结果:

v0
nil	newv2
newv1	nil
[Finished in 0.1s]

执行mytable.newk="newv2"时,因为表中设置了元方法__newindex,而且是给表一个缺少的索引值newk,所以调用元方法而不进行赋值;执行mytable.k1 = "newv1"时,k1是已存在的,所以直接赋值。

rawset (table, index, value)
  功能:设置表中指定索引的值,此函数不会调用任何元表的方法,此函数将返回table
例(更新表):

mytable = setmetatable({k1 = "v1"}, {
  __newindex = function(mytable, key, value)
                rawset(mytable, key, "\""..value.."\"")

  end
})

mytable.k1 = "new v"
mytable.k2 = 4

print(mytable.k1,mytable.k2)

结果:

new v	"4"

在上述代码中,_newindex指向一个自定义函数,其中将本应该新建给元表的索引新建给了mytable,是的没有table添加了新的索引k2,更新了mytable。

表操作符
insert(table,newkey,newvalue)
为表添加操作符,newkey后的(key,value)向后移动
__add
表相加

local j=3
mytable = setmetatable({ 1, 2, 3 }, {	
  __add = function(mytable, newtable)
    for i = 1, 3 do
    	j=j+1
      table.insert(mytable, j,newtable[i])
      print(j)
    end
    return mytable
  end
})
secondtable = {4,5,6}

mytable = mytable + secondtable
for k,v in ipairs(mytable) do
	print(k,v)
end
__add对应的运算符 ‘+’.
__sub对应的运算符 ‘-’.
__mul对应的运算符 ‘*’.
__div对应的运算符 ‘/’.
__mod对应的运算符 ‘%’.
__unm对应的运算符 ‘-’.
__concat对应的运算符 ‘…’.
__eq对应的运算符 ‘==’.
__lt对应的运算符 ‘<’.
__le对应的运算符 ‘<=’.

__call 元方法
用来计算{表元素之和+元表元素之和}

function t_maxn(t)--计算表长
    local mn = 0
    for k, v in pairs(t) do
        if mn < k then
            mn = k
        end
    end
    return mn
end
mytable = setmetatable({67},{--定义元方法__call
	__call = function(mytable,newtable)
		sum=0
		for i=1,t_maxn(mytable) do --计算表元素之和
			sum = sum+mytable[i]
		end
		for j=1,t_maxn(newtable) do --表元素之和加上元表元素之和
			sum=sum+newtable[j]
		end
		return sum
	end
})
newtable = {13,40,64}
print(mytable(newtable))

结果:184

__tostring 元方法
用于修改表的输出行为
例(修改表的输出为和)

mytable = setmetatable({23,43,54,65},{
__tostring = function(mytable)
	sum = 0
	for k,v in pairs(mytable) do 
		sum =sum+v
		end
	return "表所有元素之和为:"..sum
end
})
print(mytable)

结果为:185
end~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值