Lua - 元表
元表是一个表,它有助于在键集和相关元方法的帮助下修改它所附加的表的行为。 这些元方法是强大的 Lua 功能,可以实现以下功能 −
为表上的运算符更改/添加功能。
当键在表中不可用时使用元表中的 __index 查找元表。
有两种重要的方法用于处理元表,包括 −
setmetatable(table,metatable) − 此方法用于为表设置元表。
getmetatable(table) − 此方法用于获取表的元表。
让我们首先看看如何将一个表设置为另一个表的元表。 如下所示。
mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)
上面的代码可以用一行来表示,如下所示。
mytable = setmetatable({},{})
_index
当元表在表中不可用时,用于查找元表的简单示例如下所示。
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
让我们逐步解释上述示例中发生的情况。
这里的表 mytable 是 {key1 = "value1"}。
为 mytable 设置了元表,其中包含 __index 的函数,我们称之为元方法。
元方法执行查找索引"key2"的简单工作,如果找到,则返回"metatablevalue",否则返回对应索引的 mytable 值。
我们可以拥有上述程序的简化版本,如下所示。
mytable = setmetatable({key1 = "value1"},
{ __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)
__newindex
当我们将 __newindex 添加到 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
你可以在上面的程序中看到,如果主表中存在一个键,它只是更新它。 当主表中的键不可用时,它会将该键添加到元表中。
另一个使用 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 设置值而不使用元表的 __newindex。 类似地,有一个 rawget 可以在不使用 __index 的情况下获得价值。
将运算符行为添加到表
使用 + 运算符组合两个表的简单示例如下所示 −
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 键包含在元表中以添加运算符 + 的行为。 键和相应的运算符表如下所示。
| 序号 | Mode & Description |
|---|---|
| 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
如果您完全了解元表的功能,您确实可以执行很多非常复杂的操作而不使用它。 因此,请尝试更多地使用元表中的元表中可用的不同选项,如示例中所述,并创建您自己的示例。

