我在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可以在后台处理它...但如果它没有,可能这是我混淆的原因。
答案 0 :(得分:2)
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
的第一次通话会收到t
和0
作为参数。对iteratorFunction
的下一次调用获取t
和从iteratorFunction
返回的第一个值,依此类推。
当你写一个"生成器"函数如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 val
,values(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
功能相同。