Reputation: 960
I just can not wrap my head around this working Lua snipplet.
This:
t = {'a', 'b', 'c'}
for k, v in next, t, nil do
print(k, v)
end
Returns this:
1 a
2 b
3 c
Can someone explain,
next
gets t
as its parameter?t
is a valid to
parameter for the for
nil
is required and accepted as a valid step?Upvotes: 4
Views: 2915
Reputation: 4264
To expand a bit on the other answers:
A more descriptive naming of the values involved in a 'generic for loop' is the following:
for k, v1, v2, … in f_step, state, k0 do … end
and it goes in a loop like
k,v1,v2,…=f_step(state,k0) ; if k==nil then break end ; k0=k ; --(…for body here…)
k,v1,v2,…=f_step(state,k0) ; if k==nil then break end ; k0=k ; --(…for body here…)
k,v1,v2,…=f_step(state,k0) ; if k==nil then break end ; k0=k ; --(…for body here…)
…
and f_step is free to modify state
in any way it likes (though pairs
/next
don't do that, and as yet another example, string.gmatch
even ignores both state
and k
entirely and keeps all varying state in a closure (think 'function' if you don't know that term yet) instead.)
Now, what pairs
does is essentially just
function pairs( t )
-- (__pairs logic goes here, omitted for brevity)
return next, t, nil
end
and the common
for k, v in pairs( t ) do … end
essentially expands to
for k, v in next, t, nil do … end
(unless t
has a metatable with __pairs
.)
Now there's two reasons why you might explicitly write next, t, nil
instead of pairs
– to confuse people who don't know about this yet, or to avoid triggering __pairs
. (To avoid triggering __index
/__newindex
, you have rawget
/rawset
, to avoid __pairs
, you explicitly write next, t, nil
. Or maybe you define function rawpairs( t ) return next, t, nil end
and use that…)
Upvotes: 7
Reputation: 960
All credits go to Egor for his answer among the comments.
From the Lua 5.3 manual:
A for statement like
for var_1, ···, var_n in explist do block end
is equivalent to the code:
do local f, s, var = explist while true do local var_1, ···, var_n = f(s, var) if var_1 == nil then break end var = var_1 block end end
So the original statement translates into an infinite while
loop, that keeps calling next()
with initial parameters next(t, nil)
, and in each iteration the second parameter is replaced by the next index in the t
table. When finally next(t, index_n)
returns nil
, the loop breaks.
This seems to me an extremely powerful way to traverse a table, as next()
can be replaced by pretty much any function giving full control over the iteration. Wow.
Upvotes: 3