所謂迭代器就是一種可以遍曆一種集合中所有元素的機制。在lua中,迭代器通常表示為函數,每調用依次函數就返回集合中的下一個元素。
1.最簡單的迭代器
首先來看c++中的迭代器,輸出vector中的所有元素。
#include <iostream>#include <vector>using namespace std;int main(){ vector<int> ivec(5,-1); for (vector<int>::iterator iter = ivec.begin(); iter!= ivec.end(); ++iter) cout<<*iter<<endl;return 1;}
下面用lua來實現。
--declare an iteratorfunction values(t)local i=0;return function() i=i+1;return t[i] endendt={-1,-1,-1,-1,-1}--create iteratoriter=values(t)while true dolocal element=iter()if element==nil then break endprint(element)end
程式中定義的迭代器就是前面說過的closure。
這個closure通常設計到兩個函數:closure本身和一個用於建立該closure的工廠(factory)函數。
用泛型for來實現則更簡單,因為它就是為這個而活的。
--for stylefor element in values(t) doprint(element)end
效果是一樣的。
2.泛型for
前面如果要使用迭代器的話就一定要建立一個closure,泛型for的話就不需要,實際上泛型for儲存著三個值:一個迭代器函數,一個恒定狀態和一個控制變數。
看之前的一個泛型for例子:
days = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"}for k,v in pairs(days) do print(k..":"..v) end
通常泛型for的文法如下:
for <var-list> in <exp-list> do <body>end
其中 <var-list>是一個或多個變數名的列表,以逗號分隔;<exp-list>是一個或多個運算式的列表,同樣以逗號分隔,通常運算式列表只有一個元素,即一句對迭代器工廠的調用。
變數列表的第一個元素稱為“控制變數”,當為nil的時候迴圈結束。
for做的第一件事就是對in後面的運算式求值,這些運算式應該返回三個值供for儲存:迭代器函數、恒定狀態和控制變數的初值。這類似於一個多元素的賦值。
3.無狀態迭代器
指的是自身不儲存任何狀態的迭代器。
在每此迭代中,for迴圈都會用恒定狀態和控制變數來調用迭代其函數,一個無狀態的迭代器可以根據這兩個值為下一次迭代生產下一個元素。
ipairs就是這樣的迭代器。
a={"one","two","three"}b={[2]="four",[3]="five",[4]="six"}for i,v in ipairs(a) doprint(i,v)endfor i,v in ipairs(b) doprint(i,v)end
結果顯示只列印a,而b沒有列印。
在這裡迭代的狀態就是要遍曆的table及當前的索引值。
lua在調用for迴圈的ipairs(a)時,會獲得3個值:迭代器iter、恒定狀態a和控制變數的初值0,然後調用iter(a,0),得到1,a[1],在第二次迭代中,繼續調用iter(a,1),
得到2,a[2],以此類推。
在遍曆b的時候,當key=1時候value就是nil,所以直接跳出迴圈不輸出任何值。