元表(metatable
)是一个表,它是使用键集和相关元方法来修改附加到的表的行为。 这些元方法是强大的Lua功能,可实现如下功能 -
__index
在表中没有键时查找元表。在处理元表时有两种重要的方法,包括 -
setmetatable(table,metatable)
- 此方法用于为表设置元表。getmetatable(table)
- 此方法用于获取表的元表。首先来看看如何将一个表设置为另一个表的元表。 如下所示 -
mytable = {} mymetatable = {} setmetatable(mytable,mymetatable)
上面的代码可以用一行表示,如下所示 -
mytable = setmetatable({},{})
下表显示了元表在表中不可用时查找元表的示例。
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
添加到metatable
时,如果表中没有键,则新键的行为将由元方法定义。 下面给出了当主表中没有索引时设置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
在上面的程序中看到,如果主表中存在一个键,它只会更新它。 当维护中的键不可用时,它会将该键添加到metatable
中。
使用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
键包含在元表中以添加运算符 +
的行为。键表和相应的操作符如下所示。
编号 | 模式 | 描述 |
---|---|---|
1 | __add |
改变运算符+ 的行为。 |
2 | __sub |
改变运算符- 的行为。 |
3 | __mul |
改变运算符* 的行为。 |
4 | __div |
改变运算符/ 的行为。 |
5 | __mod |
改变运算符% 的行为。 |
6 | __unm |
改变运算符- 的行为。 |
7 | __concat |
改变运算符.. 的行为。 |
8 | __eq |
改变运算符== 的行为。 |
9 | __lt |
改变运算符< 的行为。 |
10 | __le |
改变运算符<= 的行为。 |
使用__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
要更改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
如果完全了解元表的功能,那么可以真正执行很多非常复杂的操作。 因此,尝试使用元表中可用的不同选项的元表更多地工作。