Lua - Metatables

metatable是一个表,它有助于在密钥集和相关元方法的帮助下修改附加到的表的行为.这些元方法是强大的Lua功能,可以启用功能:

  • 更改/添加功能到表上的运算符.

  • 使用metatable中的__index表中的密钥不可用时查找元表.

处理元表时有两个重要的方法,包括 :

  • setmetatable(table,metatable) : 此方法用于为表格设置元表.

  • getmetatable(table) : 此方法用于获取表的元表.

让我们首先看一下如何将一个表设置为另一个表的元表.它显示如下.

mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)


上面的代码可以用一行表示,如下所示.

mytable = setmetatable({},{})


_index

一个简单的metatable示例,用于查找表中没有的元表如下所示.

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

print(mytable.key1,mytable.key2)


当我们运行上述程序时,我们无线我将得到以下输出.

value1 metatablevalue


让我们解释一下上面的例子中步骤发生了什么.

  • 这里的表格是 {key1 ="value1"} .

  • 为mytable设置了Metatable,其中包含__index的函数,我们将其称为元方法.

  • metamethod执行查找索引"key2"的简单工作,如果找到它,则返回"metatablevalue",否则返回相应索引的mytable值.

我们可以拥有上述程序的简化版本,如下所示.

mytable = setmetatable({key1 = "value1"}, 
   { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)


__ newindex

当我们将__newindex添加到metatable时,如果表中没有键,则行为新密钥的vior将由元方法定义.下面给出了当主表中没有索引时设置metatable索引的简单示例.

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

print(mytable.key1)

mytable.newkey = "new value 2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "new  value 1"
print(mytable.key1,mymetatable.newkey1)


当你运行上面的程序时,你得到以下输出.

value1
nil	new value 2
new  value 1	nil


您可以在上面的程序中看到,如果是key存在于主表中,它只是更新它.当维护中的密钥不可用时,它会将该密钥添加到元表中.

使用rawset函数更新同一个表的另一个示例如下所示.

mytable = setmetatable({key1 = "value1"}, {

   __newindex = function(mytable, key, value)
      rawset(mytable, key, ""..value.."")
   end
})

mytable.key1 = "new value"
mytable.key2 = 4

print(mytable.key1,mytable.key2)


当我们运行上述程序时,我们将得到以下输出.

new value	"4"


rawset设置值而不使用metatable的__newindex.类似地,rawget在不使用__index的情况下获取值.

向表添加运算符行为

使用&plus组合两个表的简单示例;运算符显示在下方 :

mytable = setmetatable({ 1, 2, 3 }, {
   __add = function(mytable, newtable)
	
      for i = 1, table.maxn(newtable) do
         table.insert(mytable, table.maxn(mytable)+1,newtable[i])
      end
      return mytable
   end
})

secondtable = {4,5,6}

mytable = mytable + secondtable

for k,v in ipairs(mytable) do
   print(k,v)
end


当我们运行上述程序时,我们将获得以下输出.

1	1
2	2
3	3
4	4
5	5
6	6


__add键包含在metatable添加operator+的行为.键表和相应的运算符如下所示.

Sr.No.Mode&说明
1

__add

更改运算符'+'的行为.

2

__ sub

更改运营商的行为' - '.

3

__ mul

更改运算符'*'的行为.

4

__ div

更改运算符'/'的行为.

5

__ mod

更改运营商'%'的行为.

6

__ unm

更改运算符' - '的行为.

7

__ concat

更改运算符'..'的行为.

8

__ eq

更改运营商的行为'=='.

9

__ lt

更改运算符'<'的行为.

10

__ le

更改运算符'< ='的行为.

__ call

使用__call语句添加方法调用的行为.一个简单的示例,它返回主表中的值与传递的表的总和.

mytable = setmetatable({10}, {
   __call = function(mytable, newtable)
   sum = 0
	
      for i = 1, table.maxn(mytable) do
         sum = sum + mytable[i]
      end
	
      for i = 1, table.maxn(newtable) do
         sum = sum + newtable[i]
      end
	
      return sum
   end
})

newtable = {10,20,30}
print(mytable(newtable))


当我们运行上述程序时,我们将获得以下输出.

70


__ tostring

要更改print语句的行为,我们可以使用__tostring元方法.一个简单的例子如下所示.

mytable = setmetatable({ 10, 20, 30 }, {
   __tostring = function(mytable)
   sum = 0
	
      for k, v in pairs(mytable) do
         sum = sum + v
      end
		
      return "The sum of values in the table is " .. sum
   end
})
print(mytable)


当我们运行上述程序时,我们将得到以下输出.

The sum of values in the table is 60


如果你完全了解元表的功能,那么你可以真正执行很多非常复杂的操作而不使用它.因此,尝试使用元表中可用的不同选项的元表进行更多工作,如示例中所述,并创建自己的样本.