Lua - 元表



元表是一个表,它通过一组键和相关的元方法来帮助修改与其关联的表的行为。这些元方法是强大的 Lua 功能,可以实现以下功能:

  • 更改/添加表格上运算符的功能。

  • 当键在表中不可用时,使用元表中的 __index 来查找元表。

在处理元表时,有两种重要的方法:

  • setmetatable(table,metatable) - 此方法用于为表设置元表。

  • getmetatable(table) - 此方法用于获取表的元表。

让我们首先了解如何将一个表设置为另一个表的元表。如下所示。

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

以上代码可以表示为一行,如下所示。

mytable = setmetatable({},{})

示例 - _index

下面是一个简单的元表示例,用于在表中找不到时查找元表。

main.lua

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 的函数,我们将其称为元方法。

  • 元方法的工作很简单,查找索引 "key2",如果找到,则返回 "metatablevalue",否则返回 mytable 对应索引的值。

我们可以将以上程序简化为如下所示。

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

示例 - __newindex

当我们在元表中添加 __newindex 时,如果表中不存在键,则新键的行为将由元方法定义。下面是一个简单的示例,在主表中不存在索引时设置元表的索引。

main.lua

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

您可以在以上程序中看到,如果键存在于主表中,则它只更新它。当键在 maintable 中不可用时,它会将该键添加到元表中。

示例 - 更新表

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

main.lua

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 在不使用元表的 __newindex 的情况下设置值。类似地,rawget 在不使用 __index 的情况下获取值。

示例 - 向表添加运算符行为

下面是一个简单的示例,使用 + 运算符组合两个表:

main.lua

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 键,以添加 + 运算符的行为。键和对应运算符的表如下所示。

序号 模式和描述
1

__add

更改 + 运算符的行为。

2

__sub

更改 - 运算符的行为。

3

__mul

更改 * 运算符的行为。

4

__div

更改 / 运算符的行为。

5

__mod

更改 % 运算符的行为。

6

__unm

更改 - 运算符的行为。

7

__concat

更改 .. 运算符的行为。

8

__eq

更改 == 运算符的行为。

9

__lt

更改 < 运算符的行为。

10

__le

更改 <= 运算符的行为。

示例 - __call

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

main.lua

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 元方法。下面是一个简单的示例。

main.lua

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

如果您完全了解元表的功能,那么您可以执行许多操作,而无需使用它,这些操作将非常复杂。因此,尝试更多地使用元表以及元表中提供的不同选项,如示例中所解释的那样,并创建您自己的示例。

广告