posted too early dang it
The format of a generic for loop (not “for pairs”) generally goes like this
for returns in iter, invariant, init do
end
returns
is just the variables that get the returns of the function iter
. The invariant state is invariant
, init
is where to start. the loop keeps going until iter returns nil.
I will use a reverse ipairs function example
local function iter(t, i)
i = i - 1
local v = t[i]
if v ~= nil then
return i, v
end
return nil
end
for i, v in iter, {"a", nil, "c"}, 4 do
print(i, v)
end
I hardcoded the length of the table + 1, so how it works is on the first iteration it goes iter(t, #t + 1)
, second one it goes iter(t, #t)
, third iter(t, #t - 1)
, and so on until t[i]
is nil, whether it be because the end of the table was reached (well, beginning since this goes in reverse lol), or because of a hole in the middle.
Now functions like ipairs and pairs are known as iterator factories or iterator generators because realistically, all they do is return the functions that do the work, and arguments for it.
pairs is as simple as
function pairs(t)
return next, t, nil
end
Now to wrap the iterator just wrote, the one that goes backwards,
local function reverse(t)
return iter, t, #t + 1
end
And use it the same as pairs or ipairs;
for i, v in reverse({"a", nil, "c"}) do
print(i, v)
end
Same exact result, but the wrapper just make it easier to read.
As for next being faster than pairs, that is literally so small difference you can’t even consider it faster. And Luau optimised pairs and ipairs but not next i don’t think.