Lua 元表(Metatable)

元表定义

元表:对table操作进行扩展的表,元表里面填的是元方法,通过setmetatable(mytable,mymetatable)函数操作可以把表和元表进行绑定,这样表(mytable)就有了你自定义的功能
例如可以自定义下面俩个功能,示例在下面有说明:

  • 计算两个table的相加操作a+b。(__add)
  • 查找不存在的索引时返回自定义字符(__index)

设置元表函数:

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

设置元表

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

可以直接写成一行

mytable = setmetatable({},{}) 

返回对象元表

getmetatable(mytable)                 -- 这回返回mymetatable

__index 元方法(__俩个’_’)

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

1.如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。

mytable = {"C#","PHP","Java","Python","Lua"} --新建一个表
--元表
--查找不存在的key时调用__index方法
--匿名函数的第一个参数是mytable,参数二是mytable的key
mymetatable = {
__index = function(mytable,key)
	if key >= 10 then
		return "More than 10"
	end
end
}
mytable =setmetatable(mytable,mymetatable)  --设置元表
print(mytable[5])
print(mytable[8])
print(mytable[10])

输出结果

Lua
nil
More than 10

如果__index包含一个表(newtable)的话,当查找的值mytable不存在时会在另一个表(newtable)里面找,若都没有就返回nil

 --新建一个表
mytable = {"C#","PHP","Java","Python","Lua"}

--新建另一个表
newtable = { }
newtable[7] = "html"
newtable[8] = "css"
newtable[9] = "ph"

--直接把newtable赋值给__index
mymetatable = {
__index = newtable

}
--设置元表
mytable =setmetatable(mytable,mymetatable)

print(mytable[5])
print(mytable[8])
print(mytable[10])

输出结果

Lua
css
nil

总结

Lua 查找一个表元素时的规则,其实就是如下 3 个步骤:
1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。

__newindex 元方法

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

更新表:

mytable = {"C#","PHP","Java","Python"}

mymetatable = {
	__newindex = function(mytable,key,value)
	print("更新了key为:"..key.."value为:"..value)
	--添加新的key-value(这里注意:如果直接写 mytable[kye] = value 相当于在表里面又添加了一对键值对,导致重复调用,Lua提供rawset来添加新的值)
	rawset (mytable,key,value)
end
}

mytable =setmetatable(mytable,mymetatable)
--修改已有的值
mytable[1] = "Lua"
--添加新的值
mytable[5] = "ABC"
print(mytable[1])
print(mytable[5])

输出结果

更新了key为:5value为:ABC
Lua
ABC

如果__newtable包含的是一个表(othertable)的话那么新添加的数据都会存放在(othertable)里面

mytable = {"C#","PHP","Java","Python"}
othertable = {}

mymetatable = {
	__newindex = othertable
}

mytable =setmetatable(mytable,mymetatable)
mytable[1] = "Lua"
mytable[5] = "ABC"
print(mytable[1]) 
print(mytable[5]) 
print(othertable[5])  

输出结果

Lua
nil
ABC

为表添加操作符

__add

mytable = {"C#","PHP","Java","Python"}
--元表
mymetatable = {
	__add = function(tab,newtab)
	--获取tab的最大key
	local maxIndex = 0;
	for k,v in pairs(tab) do
		if(k>maxIndex) then
			maxIndex = k
		end
	end
	--把表二的值添加到表一里面
	for k,v in pairs(newtab) do
		maxIndex = maxIndex+1
		table.insert(tab,maxIndex,v)
	end
	return tab
end
}
--设置元表
mytable  = setmetatable(mytable,mymetatable)
--新建一个表
newtable= {"ABC","Lua","C++"}
--俩表相加
mytable= mytable+newtable
--遍历相加后的结果
for k,v in pairs(mytable) do
	print(k,v)
end

输出结果:

1 C#
2 PHP
3 Java
4 Python
5 ABC
6 Lua
7 C++

补充:
当有俩个table相加的时候,只要其中一个有定义元表即可,相加的顺序可以颠倒如上面的例子,mytable+newtable和newtable+mytable都可以执行只是输出顺序不同而已

表中对应的操作列表如下:(注意:__是两个下划线)
Lua 元表(Metatable)_第1张图片

__call 元方法

当定义了__call元方法时,table可以当成函数来使用可以传递(多个)参数,返回参数

mytable = {"C#","PHP","Java","Python"}

mymetatable = {
--第一个参数是mytable表,其他的是函数的参数,参数可以是表
__call = function(tab,arg1,arg2)
	print(arg1.." - " ..arg2)
	return arg1*arg2,arg1/arg2
end

}
--设置元表
mytable = setmetatable(mytable,mymetatable)

a , b = mytable(10,5)
print(a)
print(b)

输出结果

10 - 5
50
2

__tostring 元方法

mytable = {"C#","PHP","Java","Python"}

--输出mytable所有值value
mymetatable = {
__tostring = function(mytable)
	local str = ""
	for k,v in pairs(mytable) do
		str = str..v.."-"
	end
	return str
end

}

mytable = setmetatable(mytable,mymetatable)
print(mytable)

执行输出结果为:

C#-PHP-Java-Python-

多个元方法

用逗号进行分割就行

mytable = {}
--元方法
mymetatable = {
__index = function(mytable,key)
	--body
end,
__tostring = function(mytable)
	--body
end
-- ... ...
}
mytable = setmetatable(mytable,mymetatable)

你可能感兴趣的:(Lua)