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

Why isn't this a valid table iterator?

我在 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

它 returns 从 a 到 b 的后续整数值,包括在内。所以我尝试通过编写以下 table 迭代器来应用相同的逻辑:

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

它 returns 第一个值是正确的,但随后它抛出一个错误,提示我无法对字符串值 (seed) 进行算术运算。但是 seed 接收的不是整数值 0 吗?发生了什么事?

因为第一个例子没有递增过程(比如a = a + 1),我的想法是lua可能会在后台处理它......但如果没有,也许这是我困惑的原因。

Read this.

seed 是迭代器函数第二个参数的错误名称。它实际上是控制变量。当你从 values 中 return 0 时,你 "seed" 它,但之后它的值在循环期间发生变化:它采用迭代器函数 returned 的第一个值。

您 return 从您的迭代器 (return state[seed+1]) 中编辑了一个字符串,因此下次调用您的迭代器函数时,它会传递该字符串。你试图在上面做数学运算,然后......该死。

泛型for接受三个参数:迭代器函数、不变状态和初始控制值。使用状态和控制值调用迭代器。迭代器然后 returns 下一个控制值,或 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 下一个 调用获得 t 第一个值 return 来自 iteratorFunction, 依此类推。

当你写一个像 values 这样的 "generator" 函数时,你只是 return 通用 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 中的值。之前我们不能这样做,因为我们需要 return 一个用于下一次循环迭代的控制变量。对于闭包,我们通过绑定到闭包的变量(又名 "upvalue")维护控制变量。

您可以使用另一种形式的带闭包的迭代器:

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 被 return 编辑。无效的 table 字段(在 last 后面)始终为 nil,因此您只需要继续。

在您的示例中传递计数器值的表单使用 return 值来更新最后一个计数器值并且通常不使用。您使用字符串形式的 table 条目更新 seed,因此下一次传递必须失败。

顺便说一句:您的 values 函数与 ipairs.

的功能相同