--[[ 7 迭代器与泛型for -- 所谓“迭代器” 就是一种可以遍历一种集合中所有元素的机制。在lua中,通常将迭代器表示为函数(例如:ipairs、pairs函数)。每调用一次函数, -- 即返回集合中的“下一个”元素。一个closure结构通常涉及到两个函数:closure本身和一个用于创建该closure的工厂函数。 -- function values(t) -- local i=0 -- return function() i=i+1 ;return t[i] end -- end -- -- values就是一个工厂。每当调用这个工厂时,它就创建一个新的closure(即迭代器本身)。这个closure将它的状态保持在其外部变量t和i中。每 --当调用这个迭代器时,它就从列表中返回下一个值。直到最后一个元素返回后,迭代器就会返回nil,以此表示迭代的结束。 -- while中使用这个迭代器: -- t={10,20,30} -- iter=values(t) --创建迭代器,这个values返回的是一个匿名函数 -- while true do -- local element=iter() --调用迭代器,iter()匿名函数返回的则是:table中的元素的值。 -- if element == nil then break end -- print(element) -- end -- --使用泛型for则更为简单。 -- t={10,20,30} -- for element in values(t) do -- print(element) -- end --使用到了 in 后面的作用域 表示元素的集合,一般是一个迭代器工厂函数。 -- --泛型for为一次迭代循环做了所有的薄记工作。它在内部保存了迭代器函数,因此不再需要iter变量。它在每次新迭代时调用迭代器,并在迭代器返回 --nil时结束循环。 -- -- -- ]]-- --[[ 7.2 泛型for的语义 -- 泛型for在循环过程内部保存了迭代器函数。实际上它保存着3个值:一个迭代器函数,一个恒定状态和一个控制变量。泛型for语法: -- for <var-list> in <exp-list> do -- <body> -- end -- -- <var-list>是一个或多个变量名的列表,以逗号分隔;<exp-list>是一个或多个表达式的列表,同样以逗号分隔,通常表达式列表只有一个元素, --即一句对迭代器工厂的调用。 -- for k,v in ipairs(t) do print(k,v) end --k,v 是变量列表;表达式列表只有一个元素ipairs(t),ipairs是迭代器,for对ipairs的调用。 -- -- --for做的第一件事情是对in后面的表达式求值。这些表达式应该返回3个值供for保存:迭代器函数,恒定状态和控制变量的初值。在初始化步骤之后, --for会以恒定状态和控制变量来调用迭代器函数。然后for将迭代器函数的返回值赋予变量列表中的变量。如果第一个返回值为nil。那么循环终止。否则 --,for执行它的循环体,随后再次调用迭代器函数,并重复这个过程。 -- -- ]]-- --[[ 7.3 无效的迭代器 -- 所谓 “无状态的迭代器”,正如其名所暗示的那样,就是一种自身不保存任何状态的迭代器。ipairs就是一个无状态的迭代器。 -- a={10,20,30} -- for k,v in ipairs(a) do -- print(k,v) -- end -- -- 迭代的状态就是需要遍历的table(一个恒定状态,它不会在循环中改变)及当前的索引值(控制变量)。ipairs(工厂)和迭代器函数: -- -- -- --local function myiter(a,i) i=i+1 local v=a[i] if v then return i,v end end function myipairs(b) return myiter,b,0 end T1={10,20,30} for k,v in myipairs(T1) do -- 存在一个疑问:myipairs()函数返回3个值,但是,为什么在for中调用的时候,myiter会自动的加载这2个 print(k,v) -- 返回的值呢?,这是for的功能,具体看下面的代码: end --下面的函数和for调用说明了,for的功能会自动将in 后面返回的值强制转换为3个值,并将它们应用到迭代器里面。 local function f1(a,b) return a+b end function g1(c) return f1,c,0 end fx,m,n=g1(10) print(m,n) --print(fx()) --则会返回错误,因为这只是单纯的对myiter的调用,里面的参数a是没有值得。 for x in g1(10) do print(x) if x == 40 then break end end -- -- -- -- -- ]]-- --当LUA调用for循环中的myipairs(T1)时,它会获得3个值:迭代器函数,myiter,恒定状态a和控制变量0。然后LUA调用myiter(T1,0), --得到1,T1[1].在第二次迭代中,继续调用myiter(T1,1),得到2,T2[2],依次类推,直至得到第一个nil元素为止。 --[[ 函数pairs与ipairs类似,也是用于遍历一个table中的所有元素。不同的是,它的迭代器函数是LUA中的一个基本函数next。 -- function pairs(t) -- return next,t,nil -- end -- --在调用next(t,k)时,k是table t的key。此调用会以table中的任意次序返回一组值:此table的下一个key,及这个key所对应的值。而调用 --next(t,nil)时,返回table的第一组值。若没有下一组值时,next返回nil。 --有些用户喜欢不通过pairs调用而直接使用next: -- for k,v in next,t do -- <loop body> -- end Lua 会自动将for循环中表达式列表的结果调整为3个值。上例中得到了next、t和nil,这也正与调用pairs(t)的结果完全一致。 --LUA 中还可以将无状态的迭代器应用于 列表,详细可以查阅相关资料。 -- -- -- ]]-- --[[ 7.4 具有复杂状态的迭代器 -- -- 7.5 真正的迭代器 -- 以上两部分的内容详细可以查看资料。 -- ]]--
Lua笔记7-迭代器和泛型for
最新推荐文章于 2019-01-26 15:18:22 发布