我正在学习Lua,使用Lua编写的第一版编程。我无法理解metatables。
这是第108页上显示的代码和解释:
Set = {} function Set.new (t) local set = {} for _, l in ipairs(t) do set[l] = true end return set end function Set.union (a,b) local res = Set.new{} for k in pairs(a) do res[k] = true end for k in pairs(b) do res[k] = true end return res end function Set.intersection (a,b) local res = Set.new{} for k in pairs(a) do res[k] = b[k] end return res end
为了帮助检查我们的示例,我们还定义了一个打印集的函数:
function Set.tostring (set) local s = "{" local sep = "" for e in pairs(set) do s = s .. sep .. e sep = ", " end return s .. "}" end function Set.print (s) print(Set.tostring(s)) end
现在,我们希望使加法运算符(
+
)计算两个集合的并集。为此,我们将安排表示集合的所有表共享一个元表,这个元表将定义它们对加法运算符的反应。我们的第一步是创建一个常规表,我们将其用作集合的元表。为了避免污染我们的命名空间,我们将它存储在Set表中:Set.mt = {} -- metatable for sets
下一步是修改Set.new函数,该函数创建集合。新版本只有一个额外的行,它将mt设置为它创建的表的元表:
function Set.new (t) -- 2nd version local set = {} setmetatable(set, Set.mt) for _, l in ipairs(t) do set[l] = true end return set end
之后,我们使用Set.new创建的每个集合都将具有与其metatable相同的表:
s1 = Set.new{10, 20, 30, 50} s2 = Set.new{30, 1} print(getmetatable(s1)) --> table: 00672B60 print(getmetatable(s2)) --> table: 00672B60
最后,我们向metatable添加了所谓的metamethod,一个描述如何执行联合的字段__add:
Set.mt.__add = Set.union
每当Lua尝试添加两个集合时,它将调用此函数,并将两个操作数作为参数。
使用metamethod,我们可以使用加法运算符来设置联合:
s3 = s1 + s2 Set.print(s3) --> {1, 10, 20, 30, 50}
当我尝试运行它时,我得到了结果:{ union, mt, intersection, tostring, new, print}
而不是s3
中的数字。似乎我已经打印了元数据的内容。有人能解释一下这里发生了什么吗?这本书描述了5.0版,我正在使用Lua 5.1。这会导致这种情况吗?
答案 0 :(得分:2)
the code you ran中存在错误,而不是您在问题中发布的代码:
在Set.tostring
第28行,您将for e in pairs(set)
更改为for e in pairs(Set)
,因此它始终显示Set
的内容,而不是给定集的内容。