Sleepy Coder |
|
再见 ~
-- Benefits of what I'm proposing: -- No need for a 'continue' or 'skip' keyword if you can control the iterator from inside the loop body (it could even allow for break-like behavior) -- With this it would be possible to skip several iterations of a loop, rather than just one-by-one if a skip or continue keyword were added -- Problem -- Lua's for loops don't let us modify the key and value (and whatever other identifier declared) passed -- to the loop body when (on the next iteration) it uses these values for the next call of the iterator for k, v in ipairs({ 1, 2, 3, 4, 5 }) do print(k, v) if k == 2 then k = k + 1 end -- we can't actually do this to "skip" the 3rd iteration, but I wish we could end -- ipairs({ 1, 2, 3, 4, 5 }) returns: iterator_function, { 1, 2, 3, 4, 5 }, 0, nil -- 1st iteration: iterator_function({ 1, 2, 3, 4, 5 }, 0, nil) -- returns 1, 1 -- 2nd iteration: iterator_function({ 1, 2, 3, 4, 5 }, 1, 1) -- returns 2, 2 -- 3rd iteration: etc... -- What I Want: for k, v, not_used1 in ipairs({ 1, 2, 3, 4, 5 }) do print(k, v, not_used1) -- we want to modify the first value passed to the next iteration if k == 2 then k = k + 1 end end -- Translation: ret = { ipairs({ 1, 2, 3, 4, 5 }) } -- first 2 items from the generator (my_pairs()) would be the iterator and item it's iterating over -- (some generators don't have items they iterate over and return nil as the 2nd arg) iter, iter_self = unpack(ret) -- remove iter and iter_self from beginning ret = { unpack(ret, 3) } -- key value is at index 3 -- create our initial k, v, not_used1 k, v, not_used1 = unpack(ret) -- the rule is that iterators stop -- iterating when the k section is nil while true do -- the table is needed because the iterator could return multiple items ret = { iter(iter_self, unpack(ret)) } -- our initial k, v, not_used1 are already in ret -- ^ this should be easier done in C when you can work with the stack, no new table on each iteration -- set our new key-value for inside the loop body k, v, not_used1 = unpack(ret) if k == nil then break end -- example loop body from above do print(k, v, not_used1) -- we can now modify the first 2 values returned of the iterator to control the loop behavior if k == 2 then k = k + 1 end end -- these may have changed, reset ret ret = { k, v, not_used1, unpack(ret, 4) } -- 4 is again, dependant on identifiers declared end -- ^ this works, but isn't nearly as pretty -- it produces: -- 1 1 nil -- 2 2 nil -- 4 4 nil -- 5 5 nil -- Considerations: -- 1) you should be able to modify whatever stateful values the iterator passes to the body of the loop -- 2) it should be noted that in order to interchangeably use generators, they must return at least 2 values on each successful iteration, some_table[k] = v is convention: for k, v pairs/ipairs({ 1, 2, 3 }) do some_table[k] = v end -- 3) this way of writing the functional for loop should allow for iterators returning varargs