generic for循环函数的代价, 成本从低到高.
首先考虑使用stateless, 也就是函数中无状态值, 状态值通常在exp-list中直接指出.
其次是使用closure, 使用non-local变量传递状态值.
再次是使用状态表存储状态.
最后是coroutine.
Simply put, a closure is a function plus all it needs to access non-local variables correctly.
Whenever possible, you should try to write stateless iterators, those that
keep all their state in the for variables.
With them, you do not create new objects when you start a loop.
If you cannot fit your iteration into this model, then you should try closures.
Besides being more elegant, typically a closure is more efficient than an iterator using tables:
1.first, it is cheaper to create a closure than a table;
2.second, access to non-local variables is faster than access to table fields.
Later we will see yet another way to write iterators, with coroutines.
This is the most powerful solution, but a little more expensive.
1. 无状态的例子
iterator 函数, 参数为状态和控制变量
factory函数, 返回iterator函数, 状态和控制变量初始值, 状态值通过exp-list直接传入, 所以对于factory函数来说是不存储state值的, 因此称为stateless .
2. 使用closure的例子, 将状态值存储在closure中.
3. 使用状态表的例子
> function iter(s,i)
>> i = i+1
>> local v = s[i]
>> if v then
>> return i,v
>> end
>> end
factory函数, 返回iterator函数, 状态和控制变量初始值, 状态值通过exp-list直接传入, 所以对于factory函数来说是不存储state值的, 因此称为stateless .
> function ipairs(s)
>> return iter, s, 0
>> end
> a = {"one", "two", "three"}
> for i,v in ipairs(a) do
>> print (i,v)
>> end
1 one
2 two
3 three
2. 使用closure的例子, 将状态值存储在closure中.
factory函数, 返回iterator匿名函数以及state状态值. state封装在iterator匿名函数中.
> function allwords()
>> local state = {line = io.read(), pos = 1} -- 使用factory函数的local变量表存储状态值, 对iterator来说就是non-local变量
>> return function (state)
>> while state.line do -- 重复直到最后一行
>> local s,e = string.find(state.line, "%w+", state.pos) -- 查找单词
>> if s then
>> state.pos = e+1
>> return string.sub(state.line, s, e) -- 返回单词
>> else -- 否则下一行
>> state.line = io.read()
>> state.pos = 1
>> end
>> end
>> return nil -- 如果没有值, iterator函数返回nil给控制变量, 因此结束generic for循环.
>> end, state
>> end
> for w in allwords() do
>> print (w)
>> end
hello nihao a
hello
nihao
a
3. 使用状态表的例子
上一个例子改一下就变成表存储state值了, 只要把iterator函数放到外面即可.
> function iterator(state) -- 因为iterator函数在外头定义, 所以没有non-local变量, 所以和上面的例子差就差在这里.
>> while state.line do
>> local s,e = string.find(state.line, "%w+", state.pos)
>> if s then
>> state.pos = e+1
>> return string.sub(state.line, s, e)
>> else
>> state.line = io.read()
>> state.pos = 1
>> end
>> end
>> return nil
>> end
>
> function allwords()
>> local state = {line = io.read(), pos = 1} -- 使用表存储state值, 同时传递给iterator函数.
>> return iterator, state
>> end
> for w in allwords() do
>> print(w)
>> end
hello nihao, yes
hello
nihao
yes