Lua中表和元表的区别

什么是 Corona 中表和元表之间的区别?有哪些元表类型?我应该如何在哪里使用它们?使用表和元表的主要目的是什么?

点赞
用户221509
用户221509

Lua中,表格是您可用于创建动态结构化数据的主要数据类型。其他语言有数组、列表、字典(键-值存储),但在Lua中,您只有表格。您可以使用tab[key]语法进行索引和存储值对基本表格执行的唯一操作,例如:

local tab = {}
tab['key1'] = 'Hello' -- 使用字符串键存储一个值
tab.key2 = 'World'    -- 这是语法糖,等同于上面的
print(tab.key1, tab['key2'])  -- 索引,语法是可以互换的

您无法对基本表格执行任何其他操作,例如将它们加起来:

local v1={x=0,y=0}
local v2={x=1,y=1}
print(v1+v2)
--> stdin:1: attempt to perform arithmetic on local 'v1' (a table value)

元表允许您修改表格的行为,指定在表格被添加、相乘、连接(..)等情况下应执行什么操作。元表只是一个表格,其中包含具有特殊键的功能,也称为元方法。您可以使用setmetatable()将元表赋给表格。例如:

local Vector = {} -- 用于矢量的元表

function Vector.__add(v1, v2) -- 向量相加时应执行的操作
    -- 创建一个新表并分配一个矢量元表
    return setmetatable({x=v1.x+v2.x, y=v1.y+v2.y}, Vector)
end
function Vector.__tostring(v) -- 矢量应如何显示
    -- 这由tostring()和print()使用
    return '{x=' .. v.x .. ',y=' .. v.y .. '}'
end

local v1 = setmetatable({x=1, y=2}, Vector)
local v2 = setmetatable({x=3, y=4}, Vector)

-- 向量相加,然后打印结果向量
print(v1 + v2) --> {x=4,y=6}

如果您想更好地了解元表,您应该绝对阅读《Lua编程》关于元表的章节

2012-06-05 07:25:51
用户513763
用户513763

Lua(Corona基于该语言)使用metatable实现不同的目的。

手册中的相关条目为第2.8节。 可以在此处此处找到一个不错的教程。

metatable只是一个像其他任何表一样的表,但是被设置为另一个表(我将在下面继续将其称为基表,以区别于其他2个表)的metatable。

metatable可以包含任何东西,但是以双下划线开头的特殊键是有趣的。在此表中为这些键设置的值将在特殊情况下被调用。取决于哪个键。最有趣的是:

  • __index:每当查找基表中不存在的键时将使用该键。这可以包含表,其中键将被查找,或者函数,该函数将传递原始表和键。这可用于在表上实现方法(OOP风格),重定向,遗漏情况,设置默认值等等
  • __newindex:只有在要在之前为nil的表中分配新键时才会使用该键。如果是一个表,将在该表中分配该键。如果是一个函数,该函数将传递原始表,键和值。这可以用于控制对表的访问,预处理数据,分配重定向。
  • __call:使您能够设置在使用例如table()的函数时调用的函数。
  • __add,__sub,__mul,__div,__mod 用于实现二进制操作,
  • __unm用于实现一元运算,
  • __concat用于实现串联(..运算符)
  • __len用于实现长度操作符(#)
  • __eq,__lt,__le用于实现比较

使用__index和co.时要知道的一个小事情:在这些方法中,您应该使用rawget和rawset以防止每次再次调用metamethod,从而导致循环。 作为一个小例子:

`` ` t = {1,2,3} - 基表 mt = {} - metatable mt.__index = function(t,k) print("__index event from "..tostring(t).." key "..k) 返回“当前不可用”} end mt.__newindex = function(t,k,v) print("__newindex event from "..tostring(t).." key: "..k.." value: "..v) if type(k) ==" string "then rawset(t,k,v:reverse()) 其他 rawset(t,k,v) end end mt.__call = function(t,...) print("call to table "..tostring(t).." with arguments: ".. table.concat({...},',')) print("All elements of the table:") for k,v in pairs(t)do print(k,v)end end setmetatable(t,mt)

t [4] =“ foo” - 这将运行__newindex方法 print(t [5]) - 这将运行__index方法 t(“ foo”,“ bar”)

  • 多个跨度的例子: t = {} mt = {} mt2 = {} setmetatable(t,mt) - 在基表上的metatable setmetatable(mt,mt2) - 第二层metatable mt.__index = function(t,k)print('key '..k..' not found in '..namelookup[t])返回getmetatable(t)[k] end - 尝试在mt中查找不存在的索引。 mt2.__index = mt.__index - 函数是可以移植编写的,可以重用。

t [1] ='A' mt [2] ='B' mt2 [3] ='C' namelookup = {[t] =“ t”,[mt] =“ mt”,[mt2] =“ mt2”} 打印(t [1],t [2],t [3],t [4])

`` `

现在这些只是愚蠢的例子,您可以进行更复杂的操作。查看示例,查看[Programming in Lua]中的相关章节(http://www.lua.org/pil/)并进行实验。试着不要混淆;)

2012-06-05 07:59:19