是否有一些聪明的方法来编写一个lua对象,以便它可以兼作迭代器?

时间:2011-05-24 16:13:51

标签: iterator lua syntactic-sugar

让我说我有一些我在别处定义的“对象”。也许它代表一组项目,但比简单的表格更复杂。无论它是什么,迭代它都是合乎逻辑的。

因此,它定义了iterator方法。所以我可以这样写:

local myObject = AbstractObject:new()

for obj in myObject:iterator() do
    obj:foo()
end

我想知道的是,如果有一些我可以做的元方法技巧,这将允许我写这个:

local myObject = AbstractObject:new()

for obj in myObject do
    obj:foo()
end

那是吗?

2 个答案:

答案 0 :(得分:3)

对你的例子做一点改动会使语义变得不那么痛苦:

local myObject = AbstractObject:new()

for obj in myObject() do
    obj:foo()
end

这样,您可以使用元表来定义__call元方法以返回myObject:interator(),代码在AbstractObject:new()中看起来像这样:

setmetatable(newobject, {__call = function() return newobject:iterator() end})

如果没有迭代器构造,您将有效地重复使用单个迭代器进行多次迭代,这意味着您需要在对象/创建闭包中保持迭代器状态,并在完成后重置它以便下一次调用将再次重启迭代。如果你真的想要这样做,那么最好的解决方案就是为特定的迭代实现编写一些东西,但这会执行泛型迭代:

local iterator

--table.pack is planned for 5.2
local pack = table.pack or function(...)
  local t = {...}
  t.n = select('#',...)
  return t
end

--in 5.1 unpack isn't in table
local unpack = table.unpack or unpack

function metamethods.__call(...)
  if not iterator then
    iterator = newobject:iterator()
  end

  local returns = pack(iterator(...))

  if returns[1] == nil then
    --iteration is finished: next call will restart iteration
    iterator = nil
  end
  return unpack(returns, 1, returns.n)
end

再次:这应该真的进行调整,以适应您的使用案例。

答案 1 :(得分:0)

in之后使用的对象必须是一个函数,通用for循环将重复调用该函数。

我不确定你是否可以使一个表或用户对象像函数一样可调用,但即使这样,问题就是你的对象只能有一个内部迭代器状态 - 即它不会允许多次迭代对象(既不是同时也不是顺序),除非你以某种方式明确地重置它。

正如Stuart所说,你可以适当地使用__call metamethod来返回迭代器,但是你必须写

for obj in myObject() do
    obj:foo()
end

这不是我们想要的。

PiL中再读一遍,我看到for循环中使用了更多的组件:不变循环状态和控制变量的当前值,它们被传递给每个迭代器函数呼叫。如果我们不在in表达式中提供它们,则会将它们初始化为nil

因此,我的想法是使用这些值来区分各个呼叫。

如果你可以为你的集合创建一个next(element)函数,它为下一个元素返回每个元素,那么实现将很简单:

metatable.__call = function(_state, _last)
    if(_last == nil) then
       return obj:first()
    else
       return obj:next(_last)
   end
end

但通常我们不会有这样的东西,然后它会变得更复杂。


我想过在这里使用协同程序,但这些仍然需要工厂方法(我们要避免)。 它会产生类似于Stuart所写的东西(即在对象本身或与对象相关的其他变量中保存迭代器状态),并使用参数和/或迭代器结果来决定何时创建/清除迭代器对象/状态。

这里没有赢得。