7 Iterators and the Generic for
- 用闭包编写迭代器可以存储状态,先写一个迭代器生成器,然后生成新的迭代器1 
 2
 3
 4function values(t) 
 local i = 0
 return function () i = i + 1; return t[i] end
 end
在while循环中使用迭代器1
2
3
4
5
6
7t = {10, 20, 30}
iter = values(t)
while true do
	local element = iter()
	if element == nil then break end
	print(element)
end
generic for专为迭代器而生1
2
3
4t = {10, 20, 30}
for element in values(t) do
	print(element)
end
打印文件中的每一个word1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function allwords()
	local line = io.read()       -- current line
	local pos = 1                -- current position in the line
	return function ()           -- iterator function
		while line do            -- repeat while there are lines
			local s, e = string.find(line, "%w+", pos)
			if s then            -- found a word?
				pos = e + 1      -- next position is after this word
				return string.sub(line, s, e) -- return the word
			else
				line = io.read() -- word not found; try next line
				pos = 1          -- restart from first position
			end
		end
		return nil               -- no more lines: end of traversal
	end
end
一旦迭代器写好,在generic for中调用极其简单:1
2
3for word in allwords() do
	print(word)
end
- generic for的语义- 1 - for var_1, ..., var_n in <explist> do <block> end 
相当于1
2
3
4
5
6
7
8
9do
	local _f, _s, _var = <explist>
	while true do
		local var_1, ..., var_n = _f(_s, _var)
		_var = var_1
		if _var == nil then break end
		<block>
	end
end
其中,var_1为控制变量,<explist>初始化出三个值:迭代器函数、不变状态、控制变量的初值,迭代器函数使用不变状态和控制变量做参数,返回的值赋给var_1, ..., var_n,如果var_1为nil则循环结束,否则执行<block>。如果f为迭代器函数,a0为控制变量初值,s为不变状态,则a1=f(s,a0),a2=f(s,a1),...
- 无状态迭代器,有状态迭代器的状态存储在闭包中,无状态迭代器的状态存储在_var中。ipairs()可实现如下:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10local function iter(a, i) 
 i = i + 1
 local v = a[i]
 if v then
 return i, v
 end
 end
 function ipairs(a)
 return iter, a, 0
 end
pairs()需用到next():1
2
3function pairs(t)
	return next, t, nil
end
next(t, k),k是table t的一个key,返回下一个key和值,next(t, nil)返回第一个键值对,没有其他键值对时返回nil。next也可以直接使用:1
2
3for k, v in next, t do
	<loop body>
end
- 链表迭代器1 
 2
 3
 4
 5
 6
 7
 8
 9
 10local function getnext(list, node) 
 if not node then
 return list
 else
 return node.next
 end
 end
 function traverse(list)
 return getnext, list, nil
 end
list本身就是链表的主节点1
2
3
4
5
6
7list = nil
for line in io.lines() do
	list = {val = line, next = list}
end
for node in traverse(list) do
	print(node.val)
end
- 迭代器的多状态可通过闭包或者将多状态打包为table实现1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18local iterator 
 function allwords()
 local state = {line = io.read(), pos = 1}
 return iterator, state
 end
 function iterator(state)
 while state.line do -- repeat while there are lines
 local s, e = string.find(state.line, "%w+", state.pos)
 if s then -- found a word?
 state.pos = e + 1
 return string.sub(state.line, s, e)
 else -- word not found
 state.line = io.read() -- try next line...
 state.pos = 1 -- ... from first position
 end
 end
 return nil -- no more lines: end loop
 end
这里将循环的状态包含在了“不变”状态state中。简单的调用:1
2
3for word in allwords() do
	print(word)
end
- true iterator,循环在函数内,参数为另一个函数,表示对迭代对象的操作1 
 2
 3
 4
 5
 6
 7
 8function allwords(f) 
 for line in io.lines() do
 for word in string.gmatch(line, "%w+") do
 f(word)
 end
 end
 end
 allwords(print)
参数为匿名函数:1
2
3
4
5local count = 0
allwords(function(w)
	if w == "hello" then count = count + 1 end
end)
print(count)
用之前的迭代器1
2
3
4
5local count = 0
for w in allwords() do
	if w == "hello" then count = count + 1 end
end
print(count)