lua 迭代器和泛型for

迭代器和闭包

  1. 迭代器可以遍历集合的每一个元素,在lua中常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。
  2. 迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是它知道来自于哪里和将要前往哪里。闭包可以实现这个任务。
  3. 闭包是一个内部函数,它可以访问一个或者多个外部函数的局部变量。每次闭包成功调用后这些局部变量都保存他们的值(状态)。
  4. 所以一个典型的闭包结构包含两个函数:一个是闭包自己,另一个是工厂(创建闭包的函数)
--一个简单的迭代器输出table的元素
local function list_iter( t )
    --list_iter是工厂函数
	local i = 0
	local n = table.getn(t)
    --在这里,t、i、n 都属于闭包外部的局部变量
    --返回闭包函数
	return function (  )
		i = i + 1
		if i <= n then
			return t[i]
		end
	end
end

local t = {10,20,30}
local iter = list_iter(t)
while true do 
	local m = iter()
	if m == nil then
		break
	end
	print(m)
end
--输出 10 20 30

泛型for

泛型for在自己内部保存迭代函数,实际上它保存三个值: 迭代函数、状态常量、控制变量

for <var-list> in <exp-list> do
    <body>
end
<var-list>是以一个或多个逗号分隔的变量名列表,<exp-list>是以一个或多个逗号分隔的表达式列表,通常情况下exp-list只有一个值:迭代工厂的调用

for k, v in pairs(t) do
    print(k, v)
end
k,v 为变量列表,pairs(t)为表达式列表

泛型for的执行过程

  • 初始化,计算in后面表达式的值,表达式应该返回泛型for需要的三个值:迭代函数、状态常量、控制变量;如果返回值不够三个用nil补齐,多出则忽略。
  • 将状态变量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化的时候获取值并传递给迭代函数)。
  • 将迭代函数返回的值赋给变量列表。
  • 如果返回的第一个值为nil,循环结束,否则执行循环体。
  • 回到第二步再次调用迭代函数。

    for var1, …, varn in exp-list do block end 等价于 do local _f, _s, _var = exp-list –_f 是迭代函数,_s 是状态常量,_var 控制变量 while true do local var1, …, varn = _f(_s, _var) _var = var1 if _var == nil then break end block end end

    –简单例子 local function square( state, control ) if state <= control then return end control = control + 1 return control, control*control end – 一开始 state = 9, control = 0, – state不变,而控制变量 control 等于square的第一个返回值,不断累加 1 for k,v in square,9,0 do print(k,v) if k == nil then break end end

pairs

function pairs(t)
    return function ( tbl, k )
    	k, v = next(tbl, k)
    	print("iter ", k,v)
    	if v then
    		return k, v
    	end
    end, t, nil
end

local tt = {}
tt[1] = 1
tt[2] = 2
tt[3] = nil
tt[4] = 4

--for k,v in pairs(tt) do
--	print(k,v)
--end

do
	local _f, _s, _var = pairs(tt) -- _f 是迭代函数,_s 是状态变量,要迭代的对象,即传入的tt,_var 是控制变量
	while true do
		local k, v = _f(_s, _var)  --执行迭代函数,返回 k,v,迭代结束时两个都是nil
		print("call iter :",k, v)
		_var = k	--刷新控制变量
		if _var == nil then
			break
		end
		print("call block :", k, v)
	end
end

--输出
--[[
iterator :      1       1
call iter :     1       1
call block :    1       1
iterator :      2       2
call iter :     2       2
call block :    2       2
iterator :      4       4
call iter :     4       4
call block :    4       4
iterator :      nil     nil
call iter :     nil     nil
]]

ipairs

local tt = {}
tt[1] = 1
tt[2] = 2
tt[3] = nil
tt[4] = 4

function ipairs(t)
    return function(a, i)
        i = i + 1
        if a[i] then
            --从这里可以看出,tt[4]不会被输出了,某个下标的元素不存在就会中断
        	print("iterator : ", i, a[i])
            return i, a[i]
        end
    end, t, 0
end

-- for i,v in ipairs(tt) do
-- 	print(i,v)
-- end

do
	local _f, _s, _var = ipairs(tt)	--_f 是迭代函数,_s 是状态变量,要迭代的对象,即传入的tt,_var 是控制变量
	while true do
		local i, v = _f(_s, _var)
		print("call iter : ", i, v)
		_var = i
		if _var == nil then
			break
		end
		print("call block : ",i, v)
	end
end

--输出
--[[
iterator :      1       1
call iter :     1       1
call block :    1       1
iterator :      2       2
call iter :     2       2
call block :    2       2
call iter :     nil     nil
]]

next

next 函数原型是 next( table [ , index] )

table 是要遍历的表

index :next返回的值即是index索引的下一个值,当index为nil时,将返回第一个索引的值,当索引号为最后一个索引或者表为空时返回nil

常用 next(table) 是否返回nil来判断表是否是空表

local a = {a = "a", b = "b", c = "c", d = "d"}
local value
while next(a, value) do
    print(next(a, value))
    value = next(a, value)
end

--输出
--[[
a       a
d       d
c       c
b       b
]]

糖果

糖果
LUA教程

Lapis框架的常用处理方法

Lapis框架的常用处理方法 Continue reading

MoonScript实现选择排序

Published on February 26, 2017

MoonScript与Redis客户端

Published on January 19, 2017