我正在学习Lua,使用的是《 Lua编程》第一版。我在理解元表时遇到了麻烦。
这是出现在第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创建的每个集合都将具有与其元表相同的表:
s1 = Set.new{10, 20, 30, 50}
s2 = Set.new{30, 1}
print(getmetatable(s1)) --> table: 00672B60
print(getmetatable(s2)) --> table: 00672B60
最后,我们在元表中添加了所谓的元方法,该字段__add描述了如何执行联合:
Set.mt.__add = Set.union
每当Lua尝试添加两个集合时,它将使用两个操作数作为参数调用此函数。
设置好元方法后,我们可以使用加法运算符进行集合并集:
s3 = s1 + s2
Set.print(s3) --> {1, 10, 20, 30, 50}
当我尝试运行它时,得到的结果是:
{ union, mt, intersection, tostring, new, print}
而不是s3
中的数字。似乎我已经打印了元表的内容。有人可以解释这里发生了什么吗?本书介绍了5.0版,而我正在使用Lua 5.1。会导致这种情况吗? 最佳答案
the code you ran中有一个错误,而不是您在问题中发布的代码中的错误:
在Set.tostring
的第28行中,将for e in pairs(set)
更改为for e in pairs(Set)
,因此它始终显示Set
的内容,而不是给定集合的内容。