Programming in Lua(Thrid Edition)笔记
7 Iterators and the Generic for
- 用闭包编写迭代器可以存储状态,先写一个迭代器生成器,然后生成新的迭代器
1
2
3
4function (t)
local i = 0
return function () i = i + 1; return t[i] end
end
在while循环中使用迭代器
1 | t = {10, 20, 30} |
generic for
专为迭代器而生
1 | t = {10, 20, 30} |
打印文件中的每一个word
1 | function allwords() |
一旦迭代器写好,在generic for
中调用极其简单:
1 | for word in allwords() do |
generic for
的语义1
for var_1, ..., var_n in <explist> do <block> end
相当于
1 | do |
其中,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 | function pairs(t) |
next(t, k)
,k是table t的一个key,返回下一个key和值,next(t, nil)
返回第一个键值对,没有其他键值对时返回nil。next也可以直接使用:
1 | for k, v in next, t do |
- 链表迭代器
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 | list = nil |
- 迭代器的多状态可通过闭包或者将多状态打包为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 | for word in allwords() do |
- 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 | local count = 0 |
用之前的迭代器
1 | local count = 0 |