首先看看一下闭合函数(closure),见如下代码:

  1. function newCounter()
  2. local i = 0       -- 非局部变量(non-local variable)
  3. return function ()  -- 闭合函数(closure)
  4. i = i +
  5. return i
  6. end
  7. end
  8.  
  9. c1 = newCounter()
  10. print(c1()) --
  11. print(c1()) --
  12.  
  13. c2 = newCounter()
  14. print(c2()) --
  15. print(c1()) --
  16. print(c2()) --

闭合函数可以用来实现迭代器(iterator)(迭代器用来遍历集合,每调用一次函数,即返回集合中的下一个元素)。

例如:遍历一个table的时候,我们经常使用如下方式。

  1. t = {'x', 'y', 'z'}
  2. for k, v in ipairs(t) do
  3. print(k .. " " .. v)
  4. end
  5. -- 打印结果
  6. -- 1 x
  7. -- 2 y
  8. -- 3 z

我们可以用while遍历集合,也可以用for,并且用for会容易很多,下面看一下for的语义:

  1. -- A for statement like
  2.  
  3. for var_1, ···, var_n in explist do block end
  4. -- is equivalent to the code:
  5.  
  6. do
  7. local f, s, var = explist
  8. while true do
  9. local var_1, ···, var_n = f(s, var)
  10. var = var_1
  11. if var == nil then break end
  12. block
  13. end
  14. end
  15. -- Note the following:
  16.  
  17. -- explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable.
  18. -- f, s, and var are invisible variables. The names are here for explanatory purposes only.
  19. -- You can use break to exit a for loop.
  20. -- The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.

注:

1 for做的第一件事就是对in后面的表达式求值,这些表达式应该返回3个值供for保存:迭代器函数(f)、恒定状态(s)、控制变量的初值(var),不足的值用nil补足。

2 在初始化之后,for会以恒定状态s和控制变量var来调用迭代函数f,然后for将迭代起的返回值赋予变量列表中的变量(var_1, var_2 ..., var_n),其中var_1称为控制变量,当返回的var_1为nil时,循环终止。

下面是书中的Lua实现ipair的例子:

  1. t3 = {"x", "y", "z"}
  2.  
  3. local function iter (a, i)
  4. i = i +
  5. local v = a[i]
  6. if v then
  7. return i, v    -- 第一个返回值是控制变量
  8. end
  9. end
  10.  
  11. function __ipairs (a)
  12. return iter, a, 0  -- 3个值,迭代器、恒定状态、控制变量。 第一次是iter(a, 0),之后则是iter(a, i)
  13. end
  14.  
  15. for i, v in __ipairs(t3) do
  16. print(i .. " " .. v)
  17. end
  18.  
  19. -- 输出结果:
  20. -- 1 x
  21. -- 2 y
  22. -- 3 z

结合上面for的语义表达式,来分析上面这段代码,__ipairs是一个工厂,生产迭代器iter,迭代器的初始参数是a和0,即恒定状态(a)和控制变量(i),iter的返回值是控制变量i和返回值a[i]。

pairs与ipairs类似,但key是无序的,它的迭代器函数是 Lua中的一个基本函数next,在调用next(t, k)时,k是table t的一个key,此调用会以table中的任意次序返回一组值,而调用next(t, nil)时,返回table的第一组值。若没有下一组值的时候,next返回nil。

  1. function pairs(t)
  2. return next, t, nil
  3. end

也可以直接使用next:

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

[Lua] 迭代器 闭合函数 与 泛型for的更多相关文章

  1. lua迭代器和泛型for浅析

    (一) 首要概念要理清: 1. 在lua中,函数是一种"第一类值",他们具有特定的词法域."第一类值"表示在lua中函数与其他传统类型的值(例如数字和字符串)具 ...

  2. Lua迭代器和泛型for

    1.迭代器与closure 在lua中,迭代器通常为函数,每调用一次函数,会返回集合中的下一个元素.每个迭代器在成功调用的时候,都需要保存一些状态,closure(闭包)完美为迭代器运用而生. fun ...

  3. Step By Step(Lua迭代器和泛型for)

    Step By Step(Lua迭代器和泛型for) 1. 迭代器与Closure:    在Lua中,迭代器通常为函数,每调用一次函数,即返回集合中的"下一个"元素.每个迭代器都 ...

  4. lua闭合函数

    function count( ... ) return function( ... ) i = i+ return i end end local func = count(...) print(f ...

  5. Lua函数以及闭合函数的理解

    Lua函数以及闭合函数的理解 来源 http://blog.csdn.net/mydad353193052/article/details/48731467 词法域和第一类型 在C/C++,C#或者J ...

  6. Lua 迭代器

    第一种:lua迭代器的实现依赖于闭包(closure)特性 1.1 第一个简单的写法 --迭代器写法 function self_iter( t ) local i = 0 return functi ...

  7. Lua学习(4)——函数

    在Lua中函数的调用方式和C语言基本相同,如:print("Hello World")和a = add(x, y).唯一的差别是,如果函数只有一个参数,并且该参数的类型为字符串常量 ...

  8. Lua学习十一----------Lua迭代器

    © 版权声明:本文为博主原创文章,转载请注明出处 Lua迭代器 - 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址 - Lu ...

  9. Lua 学习之基础篇二<Lua 数据类型以及函数库 汇总>

    引言 前面讲了运算符,这里主要对Lua的数据处理相关的数据类型和函数库进行总结归纳,后面会再接着单独分开讲解具体使用. 首先因为Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值. 值可以存储 ...

随机推荐

  1. mkdirp——递归创建目录及其子目录

    如果要创建目录A并创建目录A的子目录B,没有用-p参数的情况下mkdir会逐个创建目录(mkdir A; mkdir A/B); 加上参数-p就可以直接创建2个目录mkdir -p A/B( 如果目录 ...

  2. Java8新特性 -- Lambda 方法引用和构造器引用

    一. 方法引用: 若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用” 要求 方法的参数和返回值类型 和 函数式接口中的参数类型和返回值类型保持一致. 主要有三种语法格式: 对象 :: ...

  3. 在Ubuntu Desktop中安装软件

    1. 安装好虚拟机后,可以先打开firefox,看是否可以访问外部的网页. 2. 如果在公司内网,可能访问不起,需要添加代理,确保可以访问外部的网页. 3. 更新软件源 sudo apt update ...

  4. Laravel中如何将单个routes.php分割成多个子文件

    随着业务逻辑越来越复杂,routes.php文件也会变得越来越庞大,为了便于管理,我们可以像管理配置文件那样将其分割成多个子文件,这实现起来很简单: // app/routes.php ... // ...

  5. Ubuntu16.04如何彻底删除Apache2

    虽然作为运维人员通常情况不建议随意删除Linux系统上面的任何软件,主要指生产环境下,测试环境也不能太随意. 但是有的时候,比如系统环境要变一变,我们就需要替换一些淘汰的软件,对此我们一般都会删除. ...

  6. datagrid 完整dom结构

    <!-- datagrid的最外层容器,可以使用$(target).datagrid('getPanel')或者$.data(target,'datagrid').panel得到这个DOM对象, ...

  7. jenkins slave 挂载

    http://blog.sina.com.cn/s/blog_13cc013b50102wiau.html

  8. P1481 魔族密码

    题目描述 风之子刚走进他的考场,就…… 花花:当当当当~~偶是魅力女皇——花花!!^^(华丽出场,礼炮,鲜花) 风之子:我呕……(杀死人的眼神)快说题目!否则……-_-### 花花:……咦好冷我们现在 ...

  9. 浅谈IC行业产业链以及贸易商在产业链中的作用  2008-10-16 12:45[转自Michael的博客]

    随着集成电路行业在中国的迅猛发展, 中国的低成本劳动力和开放的引入外资政策, 使得全球电子产品生产厂商为了降低成本, 增加产品市场竞争力, 纷纷在中国设立生产线, 而中国不断膨胀的购买力也促进了这一产 ...

  10. jquery 中的dom操作

    jquery DOM 分为元素操作.属性操作.样式操作. 一.元素操作 1.查找 ①工具:jQuery选择器 2.创建和添加 ①代码格式:变量 = $('要创建的元素'): 注意点: 1 要使用标准的 ...