Lua语言基础汇总(6)-- 迭代器与泛型for

前言

迭代器就是一种可以遍历一种集合中所有元素的机制,在Lua中,通常将迭代器表示为函数。每调用一次函数,就返回集合中的“下一个”元素。每个迭代器都需要在每次成功调用之后保存一些状态,这样才能知道它所在的位置及如何走到下一个位置,通过之前博文的总结,闭包对于这样的任务提供了极佳的支持。现在我们就用代码来实现一个简单的迭代器。


1

2

3

4

5

6

7

8

9

10

11

12

function values(tb)

     local i = 0

     return function ()

          i = i + 1

          return tb[i]

     end

end

 

local testTb = {10, 20, 30}

for value in values(testTb) do

     print(value)

end

这就是一个最简单的迭代器,使用闭包来完成整个任务;这只是一个简单的例子,接下来,再看看泛型for的语义。

泛型for的语义

泛型for比较复杂,它在循环过程内保存了迭代器函数。它实际上保存着3个值:一个迭代器函数、一个恒定状态和一个控制变量。接下来,分别进行总结。

泛型for的语法如下:


1

2

3

for <var-list> in <exp-list> do

     <body>

end

其中,<var-list>是一个或多个变量名的列表,以逗号分隔;<exp-list>是一个或多个表达式的列表,同样以逗号分隔。通常表达式列表只有一个元素,即一句对迭代器函数的调用。例如:


1

for k, v in pairs(t) do print(k, v) end

for做的第一件事就是对in后面的表达式求值,这些表达式应该返回3个值供for保存:迭代器函数、恒定状态和控制变量的初值。这里和多重赋值是一样的,只有最后一个表达式才会产生多个结果,并且只会保留前3个值,多余的值会被丢弃;而不够的话,就以nil补足。

在初始化完成以后,for会以恒定状态和控制变量来调用迭代器函数。然后for将迭代器函数的返回值赋予变量列表中的变量。如果第一个返回值为nil,那么循环就终止,否则,for执行它的循环体,随后再次调用迭代器函数,并重复这个过程。在前言部分的代码中,只是返回了迭代器函数,并没有返回恒定状态和控制变量。下面通过代码来说明这个问题,比如:


1

2

3

4

5

6

7

8

9

10

11

for var_1, ..., var_n in <explist> do <block> end -- 就等价于以下代码:

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

end

无状态的迭代器

所谓“无状态的迭代器”,就是一种自身不保存任何状态的迭代器。因此,我们可以在多个循环中使用同一个无状态的迭代器,避免创建新的闭包的开销。

在每次迭代中,for循环都会用恒定状态和控制变量来调用迭代器函数。一个无状态的迭代器可以根据这两个值来为下次迭代生成下一个元素。这类迭代器的代表就是ipairs。它可以用来迭代一个数组的所有元素。如下述演示代码:


1

2

3

4

local aTb = {"One""Two""Three"}

for i, v in ipairs(aTb) do

     print(i, v)

end

在这里,迭代器状态就是需要遍历的table(一个恒定状态,它不会在循环中改变)及当前的索引值(控制变量)。我们可以使用Lua代码来实现ipairs,大概就如下代码:


1

2

3

4

5

6

7

8

9

10

11

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与ipairs类似,也是用于遍历一个table中的所有元素。不同的是,它的迭代器函数是Lua中的一个基本函next。


1

2

3

function pairs(a)

     return next, t, nil

end

在调用next(t, k)时,k是table t的一个key。此调用会以table中的任意次序返回一组值:此table的下一个key,及这个key所对应的值。而调用next(t, nil)时,返回table的第一组值。若没有下一组值时,next返回nil。所以,我们也可以使用next来判断一个table是否为空。

对于大家经常迷惑的ipairs和pairs的区别,在这里就能看的一清二楚了,ipairs只能用于遍历index是整型的table,同时,由于ipairs返回的控制变量初值为0,这就决定了,ipairs只能访问index从1开始的key和value;ipairs不能返回nil,当key对应的值为nil时,就直接终止遍历;而pairs则没有要求。

当然了,有了无状态的迭代器,就有了有状态的迭代器了,有状态的迭代器就是专门用一个table来保存状态;在无状态的迭代器中,我们每一次都是迭代一个table,这个table就是一个无状态的table,它不会再遍历的过程中发生变化,而有状态的迭代器,则会在遍历的过程中对迭代的table进行变更,迭代的table的状态也随之发生了变化。这里不做详细的总结。

来源网址:http://www.jellythink.com/archives/506

Lua语言基础汇总(6)-- 迭代器与泛型for,布布扣,bubuko.com

时间: 2024-10-19 15:54:30

Lua语言基础汇总(6)-- 迭代器与泛型for的相关文章

[转]Lua语言基础汇总(6)-- 迭代器与泛型for

前言 迭代器就是一种可以遍历一种集合中所有元素的机制,在Lua中,通常将迭代器表示为函数.每调用一次函数,就返回集合中的“下一个”元素.每个迭代器都需要在每次成功调用之后保存一些状态,这样才能知道它所在的位置及如何走到下一个位置,通过之前博文的总结,闭包对于这样的任务提供了极佳的支持.现在我们就用代码来实现一个简单的迭代器. 1 2 3 4 5 6 7 8 9 10 11 12 function values(tb)      local i = 0      return function (

Lua语言基础汇总(3) -- 语句

赋值 赋值的基本含义是修改一个变量或一个table中字段的值,这个和其它语言没有多少区别,但是对于Lua,有一个特性,它允许“多重赋值”,也就是一下子将多个值赋予多个变量,例如以下代码: 1 2 3 local x1, x2 = 2, 4 print(x1)     -->2 print(x2)     -->4 在多重赋值中,Lua先对等号右边的所有元素求值,然后才执行赋值,例如以下用法,可以非常简便的交换两个元素的值: 1 2 3 4 local x1, x2 = 2, 4 x1, x2 

[转]Lua语言基础汇总(3) -- 语句

赋值 赋值的基本含义是修改一个变量或一个table中字段的值,这个和其它语言没有多少区别,但是对于Lua,有一个特性,它允许“多重赋值”,也就是一下子将多个值赋予多个变量,例如以下代码: 1 2 3 local x1, x2 = 2, 4 print(x1)     -->2 print(x2)     -->4 在多重赋值中,Lua先对等号右边的所有元素求值,然后才执行赋值,例如以下用法,可以非常简便的交换两个元素的值: 1 2 3 4 local x1, x2 = 2, 4 x1, x2 

Lua语言基础汇总(5) -- 闭包

前言 在很多语言中都有闭包的概念,而在这里,我将主要对Lua语言的闭包概念进行分析与总结.希望对大家学习Lua有帮助. 什么是闭包? 闭包在Lua中是一个非常重要的概念,闭包是由函数和与其相关的引用环境组合而成的实体.我们再来看一段代码: 1 2 3 4 5 6 7 8 9 10 11 function newCounter()      local i = 0      return function () -- 匿名函数           i = i + 1           retur

[转]Lua语言基础汇总(5) -- 闭包

前言 在很多语言中都有闭包的概念,而在这里,我将主要对Lua语言的闭包概念进行分析与总结.希望对大家学习Lua有帮助. 什么是闭包? 闭包在Lua中是一个非常重要的概念,闭包是由函数和与其相关的引用环境组合而成的实体.我们再来看一段代码: 1 2 3 4 5 6 7 8 9 10 11 function newCounter()      local i = 0      return function () -- 匿名函数           i = i + 1           retur

Lua语言基础汇总(13)-- Lua中一些常用的库

前言 这篇文章将会来一些比较轻松的内容,就是简单的介绍一下Lua中几个常用的库.简单的说就是几个API的介绍.所以说,看起来比较容易,也没有多大的分量.就是纯粹的总结.使用库就是为了方便我们的开发,提高开发效率,同时也能保证代码的质量.希望大家以后也不要重复造轮子了. 数学库 数学库(math)由一组标准的数学函数构成.这里主要介绍几个常用的函数,其它的大家可以自行百度解决. 1. 三角函数(sin,cos,tan……) 所有的三角函数都使用弧度单位,可以用函数deg(角度)和rad(弧度)来转

Lua语言基础汇总(9)-- Lua中__index和__newindex实践

前言 本文将通过几个简单的实例演示,巩固对__index和__newindex的理解,同时加深对Lua中元表和元方法的理解,如果对Lua的元表和元方法还不是很熟悉的话,请参考这篇文章:<Lua中的元表与元方法>. 具有默认值的table 我们都知道,table中的任何字段的默认值都是nil,但是通过元表,我们可以很容易的修改这一规定,代码如下: 1 2 3 4 5 6 7 8 9 function setDefault(tb, defaultValue)      local mt = {__

Lua语言基础汇总(12)-- Lua中的面向对象编程

简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 1 2 3 4 5 6 7 8 9 10 11 12 local tb1 = {a = 1, b = 2} local tb2 = {a = 1, b = 2} local tb3 = tb1   if tb1 == tb2 then      print("tb1 == tb2") else      print("tb1 ~= tb2") end   tb3.a = 3 pri

Lua语言基础汇总(7) -- 协同程序

前言 协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.从概念上讲,线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行.就是说,一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停. 协同程序基础 Lua将所有关于协同程序的函数放置在一个名为“coroutine”的table中.函数create