Lua教程(五):迭代器和泛型for
1.迭代器与Closure:
在Lua中,迭代器通常为函数,每调用一次函数,即返回集合中的“下一个”元素。每个迭代器都需要在每次成功调用之间保持一些状态,这样才能知道它所在的位置和下一次遍历时的位置。从这一点看,Lua中closure机制为此问题提供了语言上的保障,见如下示例:
functionvalues(t) locali=0 returnfunction() i=i+1 returnt[i] end end t={10,20,30} it=values(t) whiletruedo localelement=it() ifelement==nilthen break end print(element) end --另外一种基于foreach的调用方式(泛型for) t2={15,25,35} forelementinvalues(t2)do print(element) end --输出结果为: --10 --20 --30 --15 --25 --35
从上面的应用示例来看,相比于while方式,泛型for的方式提供了更清晰的实现逻辑。因为Lua在其内部替我们保存了迭代器函数,并在每次迭代时调用该隐式的内部迭代器,直到迭代器返回nil时结束循环。
2.泛型for的语义:
上面示例中的迭代器有一个明显的缺点,即每次循环时都需要创建一个新的closure变量,否则第一次迭代成功后,再将该closure用于新的for循环时将会直接退出。
这里我们还是先详细的讲解一下Lua中泛型(for)的机制,之后再给出一个无状态迭代器的例子,以便于我们的理解。如果我们的迭代器实现为无状态迭代器,那么就不必为每一次的泛型(for)都重新声明一个新的迭代器变量了。
泛型(for)的语法如下:
for<var-list>in<exp-list>do <body> end
为了便于理解,由于我们在实际应用中<exp-list>通常只是包含一个表达式(expr),因此简单起见,这里的说明将只是包含一个表达式,而不是表达式列表。现在我们先给出表达式的原型和实例,如:
functionipairs2(a) returniter,a,0 end
该函数返回3个值,第一个为实际的迭代器函数变量,第二个是一个恒定对象,这里我们可以理解为待遍历的容器,第三个变量是在调用iter()函数时为其传入的初始值。
下面我们再看一下iter()函数的实现,如:
localfunctioniter(a,i) i=i+1 localv=a[i] ifvthen returni,v else returnnil,nil end end
在迭代器函数iter()中返回了两个值,分别对应于table的key和value,其中key(返回的i)如果为nil,泛型(for)将会认为本次迭代已经结束。下面我们先看一下实际用例,如:
functionipairs2(a) returniter,a,0 end
localfunctioniter(a,i) i=i+1 localv=a[i] ifvthen returni,v else returnnil,nil end end
a={"one","two","three"} fork,vinipairs2(a)do print(k,v) end --输出结果为: --1 one --2 two --3 three