4

我正在学习 Lua,使用的是Programming in Lua, first edition。我无法理解元表。

这是出现在第 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。这可能是造成这种情况的原因吗?

4

1 回答 1

3

您运行的代码中有一个错误,而不是您在问题中发布的代码:

Set.tostring第 28 行,您更改for e in pairs(set)for e in pairs(Set),因此它始终显示 的内容Set,而不是给定集合的内容。

于 2013-08-22T10:54:59.863 回答