为什么这不是一个有效的表迭代器?

时间:2015-08-09 18:59:39

标签: loops lua iterator lua-table

我在lua课程中看到了这个例子:

function fromto(a, b)
  return
    function(state, seed)
      if (seed >= state) then return nil
      else return seed+1 end
    end, b, a-1
end

它返回从a到b的后续整数值,包括端点。所以我尝试通过编写下面的表迭代器来应用相同的逻辑:

function values(t) -- t is a table
  return
    function(state, seed)
      return state[seed+1]
    end, t, 0
end

它正确地返回第一个值,但是它会抛出一个错误,说我不能在字符串值(seed)中进行算术运算。但是不是seed接收值0,这是一个整数?发生了什么事?

由于第一个例子没有增加过程(如a = a + 1),我的想法是lua可以在后台处理它...但如果它没有,可能这是我混淆的原因。

2 个答案:

答案 0 :(得分:2)

Read this

seed是迭代器函数的第二个参数的错误名称。它实际上是控制变量。你"种子"它从values返回0时,但在此之后它的值在循环期间发生变化:它取自迭代器函数返回的第一个值。

您从迭代器(return state[seed+1])返回了一个字符串,因此下次调用迭代器函数时,会传递该字符串。你试图对它做数学,然后......嗯。

泛型for有三个参数:迭代器函数,不变状态和初始控制值。使用状态和控制值调用迭代器。迭代器然后返回下一个控件值,或nil以指示迭代已完成。

t = {"foo","bar","zip","zap"}

local function iteratorFunction (state, index)
  index = index + 1
  local val = state[index]
  if val == nil then return nil end
  return index, val
end

for k, v in iteratorFunction, t, 0 do
    print(k,v)
end

因此,对iteratorFunction的第一次通话会收到t0作为参数。对iteratorFunction下一次调用获取titeratorFunction 返回的第一个值,依此类推。

当你写一个"生成器"函数如values,您只需返回泛型for循环所需的三个初始值,以便在使用该迭代器时您的代码更简洁:

function values(t)
    local function iteratorFunction (state, index)
      index = index + 1
      local val = state[index]
      if val == nil then return nil end
      return index, val
    end
    return iteratorFunction, t, 0 -- the same three values used in the for loop above
end

for k, v in values(t) do
    print(k,v)
end

泛型for唯一需要的参数是迭代器函数。不变状态和控制变量可以是nil,如果你的迭代逻辑在闭包中完成,你可能会这样做:

function values(t)
    local index = 0
    -- our iterator function is a closure bound to `index` and `t`
    local function iteratorFunction()
      index = index + 1
      local val = t[index]
      if val == nil then return nil end
      return index, val
    end
    return iteratorFunction, t, 0 -- the same three values used in the for loop above
end

for k, v in values(t) do
    print(k,v)
end

如果您将return index, val更改为return valvalues(t)现在只会迭代t中的值。之前我们无法做到这一点,因为我们需要为下一个循环迭代返回一个控制变量。通过闭包,我们通过绑定到闭包的变量来维护控制变量(又名" upvalue")。

答案 1 :(得分:1)

您可以使用带闭包的其他形式的迭代器:

local function values(t)
    local i = 0
    return function()
        i = i + 1
        return t[i]
    end
end

for x in values({1, 2, 3}) do
    print(x)
end
  

1 2 3

迭代器一直持续到nil返回。无效的表格字段(最后一个)总是为零,所以你必须继续前进。

示例中带有计数器值的表单使用返回值来更新最后一个计数器值,并且通常不会使用。您使用作为字符串的表条目更新seed,因此下一次传递必须失败。

顺便说一下:您的功能与ipairs功能相同。