Lua 基础教程(十五)元表

150 阅读4分钟

Lua 基础教程(十五)元表

hudson 译 原文

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 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添加到元表中时,如果表中没有键,新键的行为将由元方法定义。当索引在主表中不可用时,可在元表中设置索引。如下示例:

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键包含在元表中,以添加运算符+的行为。下表列出了键和相应运算符:

好的,以下是带有序号和中文翻译的表格:

序号方法名描述
1__add更改 '+' 运算符的行为。
2__sub更改 '-' 运算符的行为。
3__mul更改 '*' 运算符的行为。
4__div更改 '/' 运算符的行为。
5__mod更改 '%' 运算符的行为。
6__unm更改一元 '-' 运算符的行为。
7__concat更改 '..' 运算符的行为。
8__eq更改 '==' 运算符的行为。
9__lt更改 '<' 运算符的行为。
10__le更改 '<=' 运算符的行为。

__call

__call语句用来添加方法调用的行为 。下面是一个简单的示例,返回主表中传递的值之和:

-- Adding behavior of method call is done using __call statement. 
-- A simple example that returns the sum of values in the main table with the passed table.

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

要更改打印语句的行为,可以使用__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

如果完全了解元表的功能,就可以执行许多操作,这些操作在不使用元表的情况下非常复杂。 因此,尝试更多地使用元表,以及其可用的不同选项,如示例中解释的那样,并创建自己的样本代码。