Programming in Lua(Thrid Edition)笔记

7 Iterators and the Generic for

  • 用闭包编写迭代器可以存储状态,先写一个迭代器生成器,然后生成新的迭代器

    1   2   3   4  
    
    function (t)  
	local i = 0  
	return function () i = i + 1; return t[i] end  
end  

—|—

在while循环中使用迭代器

1  
2  
3  
4  
5  
6  
7  
t = {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  
4  
t = {10, 20, 30}  
for element in values(t) do  
	print(element)  
end  

—|—

打印文件中的每一个word

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
function allwords()  
	local line = io.read()         
	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  
3  
for 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  
9  
do  
	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_1nil则循环结束,否则执行<block>。如果f为迭代器函数,a0为控制变量初值,s为不变状态,则a1=f(s,a0),a2=f(s,a1),...

  • 无状态迭代器,有状态迭代器的状态存储在闭包中,无状态迭代器的状态存储在_var中。ipairs()可实现如下:

    1   2   3   4   5   6   7   8   9   10  
    
    local 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  
3  
function pairs(t)  
	return next, t, nil  
end  

—|—

next(t, k),k是table t的一个key,返回下一个key和值,next(t, nil)返回第一个键值对,没有其他键值对时返回nil。next也可以直接使用:

1  
2  
3  
for k, v in next, t do  
	<loop body>  
end  

—|—

  • 链表迭代器

    1   2   3   4   5   6   7   8   9   10  
    
    local 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  
7  
list = 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   18  
    
    local 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  
3  
for word in allwords() do  
	print(word)  
end  

—|—

  • true iterator,循环在函数内,参数为另一个函数,表示对迭代对象的操作

    1   2   3   4   5   6   7   8  
    
    function 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  
5  
local count = 0  
allwords(function(w)  
	if w == "hello" then count = count + 1 end  
end)  
print(count)  

—|—

用之前的迭代器

1  
2  
3  
4  
5  
local count = 0  
for w in allwords() do  
	if w == "hello" then count = count + 1 end  
end  
print(count)  

—|—

糖果

糖果
LUA教程

如果不小心安装错 SQL Server 为 Evaluation 的版本,要小心当超过 180 天之后,系统就会无法正常使用了 这几天遇到一个蛮特别的案例,原本收到的问题是 “维护计划” 忽然无法使用,即便是里面没有任何的Task,都无法顺利地执行。但从对方所提供的错误消...… Continue reading

PLUM NIZ静电容键盘怎么样?

Published on September 25, 2020

程序员如何选择合适的机械键盘

Published on September 18, 2020