迭代器和闭包

迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。

迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是他知道来自于哪里和将要前往哪里。闭包提供的机制可以很容易实现这个任务。记住:闭包是一个内部函数,它可以访问一个或者多个外部函数的外部局部变量。每次闭包的成功调用后这些外部局部变量都保存他们的值(状态)。当然如果要创建一个闭包必须要创建其外部局部变量。所以一个典型的闭包的结构包含两个函数:一个是闭包自己;另一个是工厂(创建闭包的函数)。

举一个简单的例子,我们为一个list写一个简单的迭代器,与ipairs()不同的是我们实现的这个迭代器返回元素的值而不是索引下标:

  1. function list_iter (t)
  2.  
  3.   local i =
  4.   local n = table.getn(t)
  5.   return function ()
  6.     i = i +
  7.     if i <= n then return t[i] end
      end
  8. end

这个例子中list_iter是一个工厂,每次调用他都会创建一个新的闭包(迭代器本身)。闭包保存内部局部变量(t,i,n),因此每次调用他返回list中的下一个元素值,当list中没有值时,返回nil.我们可以在while语句中使用这个迭代器:

  1. t = {, , }
  2. iter = list_iter(t) -- creates the iterator
  3. while true do
  4.   local element = iter() -- calls the iterator
  5.   if element == nil then break end
  6.   print(element)
  7. end

我们设计的这个迭代器也很容易用于范性for语句。

  1. t = {, , }
  2. for element in list_iter(t) do
  3.   print(element)
  4. end

范性for为迭代循环处理所有的薄记(bookkeeping):首先调用迭代工厂;内部保留迭代函数,因此我们不需要iter变量;然后在每一个新的迭代处调用迭代器函数;当迭代器返回nil时循环结束。

范性for的语义

前面我们看到的迭代器有一个缺点:每次调用都需要创建一个闭包,大多数情况下这种做法都没什么问题,然而在有些情况下创建闭包的代价是不能忍受的。在这些情况下我们可以使用范性for本身来保存迭代的状态。

前面我们看到在循环过程中范性for在自己内部保存迭代函数,实际上它保存三个值:迭代函数,状态常量和控制变量.下面详细说明。

范性for的文法如下:

  1. for <var-list> in <exp-list> do
  2.   <body>
  3. End

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

  1. for k, v in pairs(t) do
  2.   print(k, v)
  3. end

变量列表k,v;表达式列表pair(t)。

我们称变量列表中第一个变量为控制变量,其值为nil时循环结束。

下面我们看看范性for的执行过程:

首先,初始化,计算in后面表达式的值,表达式应该返回范性for需要的三个值:迭代函数,状态常量和控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略。

第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。

第三,将迭代函数返回的值赋给变量列表。

第四,如果返回的第一个值为nil循环结束,否则执行循环体。

第五,回到第二步再次调用迭代函数。

更精确的来说:

  1. for var_1, ..., var_n in explist do block end

等价于:

  1. do
  2. local _f, _s, _var = explist
  3. while true do
  4.   local var_1, ... , var_n = _f(_s, _var)
  5.   _var = var_1
  6.   if _var == nil then break end
  7.     block
  8.   end
  9. end

如果我们的迭代函数是f,状态常量是s,控制变量的初始值是a0,那么控制变量将循环:a1=f(s,a0)、a2=f(s,a1)、⋯⋯,直到ai=nil。

无状态的迭代器

每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。这种无状态迭代器的典型的简单的例子是ipairs,他遍历数组的每一个元素。

  1. a = {"one", "two", "three"}
  2. for i, v in ipairs(a) do
  3. print(i, v)
  4. end

迭代的状态包括被遍历的表(循环过程中不会改变的状态常量)和当前的索引下标(控制变量),ipairs和迭代函数都很简单,我们在Lua中可以这样实现:

  1. function iter (a, i)
  2. i = i +
  3. local v = a[i]
  4. if v then
  5. return i, v
  6. end
  7. end
  8.  
  9. function ipairs (a)
  10. return iter, a,
  11. end

当Lua 调用 ipairs(a)开始循环时,他获取三个值:迭代函数 iter,状态常量 a 和控制变量初始值0;然后Lua调用iter(a,0)返回1,a[1](除非a[1]=nil);第二次迭代调用iter(a,1)返回2,a[2]⋯⋯直到第一个非nil元素。

多状态的迭代器

很多情况下,迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,最简单的方法是使用闭包,还有一种方法就是将所有的状态信息封装到table内,将table作为迭代器的状态常量,因为这种情况下可以将所有的信息存放在table内,所以迭代函数通常不需要第二个参数。

下面我们写allwords迭代器,不适用闭包,而是使用带有两个域(line,pos)的table。

开始的迭代函数很简单,必须返回迭代函数和初始状态。

  1. local iterator -- to be defined later
  2. function allwords()local state = {line = io.read(), pos = }
  3. return iterator, state
  4. end

真正的处理工作是在迭代函数内完成:

  1. function iterator (state)
  2.   while state.line do --repeat while there are lines
  3.   --search for next word
  4.   local s,e = string.find(state.line,”%w+”,state.pos)
  5.     if s then
  6.       state.pos = e+
  7.       return string.sub(state.line,s,e)
  8.     else
  9.       state.line = io.read()
  10.       state.pos =
  11.     end
  12.   end
  13.   return nil
  14. end

我们应该尽可能的写无状态的迭代器,因为这样循环的时候由 for 来保存状态,如果不能用无状态的迭代器实现,应尽可能适用闭包;尽可能不要适用table这种方式。

Lua语法基础(3)--迭代器和泛型for的更多相关文章

  1. Lua语法基础(1)---简介、基本数据类型、表达式

    我觉得我已经陷入了一个坑内.因为,安装了Lua和SublimeText3编辑器之后,怎么使自己编写的lua代码在untiy内运行起来,是个我完全不了解的机制.先放一放吧.首先,来回顾一下Lua的语法基 ...

  2. Lua语法基础(一)

    1. 注释 -- 单行注释 --[[ 多行注释 --]] 2. 运行方式     (1)交互式运行         命令行下 lua进入交互模式     (2)命令行运行         lua + ...

  3. Lua语法基础(2)--基本语法、函数

    上一篇编辑编辑着,发现,缩进出了问题.作为一个不是强迫症的人,实在是忍受不了同一级内容不同缩进方式的槽点,于是重开一篇吧.(万幸,这样的文章也只有我自己看.) 第四 基本语法 赋值语句,Lua可以对多 ...

  4. lua语法 - 基础篇

    1. 注释 单行注释:--,类似于C++的// 多行注释:--[[ ... ]],类似于C++的/*...*/ 2. 语句 分隔符:分号或者空格,一般多行写一起,建议用分号 语句块:do ... en ...

  5. Java语法基础学习DayTwelve(泛型)

    一.泛型(Generic)在集合中的使用 1.作用 (1)解决元素存储的安全问题 (2)解决获取数据元素时,需要类型强转的问题 2.代码案例 //在集合没有使用泛型的情况下 List list = n ...

  6. python语法基础-函数-迭代器和生成器-长期维护

    ###############    迭代器    ############## """ 迭代器 这是一个新的知识点 我们学习过的可以迭代的对象有哪些? list str ...

  7. Lua语法基础(二)

    1. 函数 1.1 函数声明 默认为全局 局部函数使用local关键字声明 1.2 参数 ...等同于Python中*args三个点表示可变参数 1.3 获取参数长度的两种方式 (1)将传入的参数.. ...

  8. Lua脚本之语法基础快速入门

    要 1.基本数据类型 2.Lua中的常用语句结构以及函数 3.Lua中的常用语句结构介绍 4.Lua中的库函数 目录[-] 一.基本数据类型 二.Lua中的常用语句结构以及函数 1.Lua中的常用语句 ...

  9. Lua学习(5)——迭代器与泛型for

    1. 迭代器 2. 泛型for语义 所谓迭代器就是一种可以遍历一种集合中所有元素的机制.在lua中,迭代器通常表示为函数,每调用依次函数就返回集合中的下一个元素.泛型for 内部保存了迭代器函数 实际 ...

随机推荐

  1. 关于js中的回调函数callback

    来源于:http://www.jianshu.com/p/6bc353e5f7a3 前言 其实我一直很困惑关于js 中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制 ...

  2. Ubuntu常用命令大全[显示桌面]

    Ubuntu常用命令大全 查看软件xxx安装内容 #dpkg -L xxx 查找软件 #apt-cache search 正则表达式 查找文件属于哪个包 #dpkg -S filename apt-f ...

  3. 【LeetCode】224. Basic Calculator

    Basic Calculator Implement a basic calculator to evaluate a simple expression string. The expression ...

  4. 完善_IO, _IOR, _IOW, _IOWR 宏的用法与解析

    _IO, _IOR, _IOW, _IOWR 宏的用法与解析  原文地址:http://www.eefocus.com/ayayayaya/blog/12-03/245777_20cdd.html 作 ...

  5. 简单解决XP共享连接数10限制(转)

    1.建立一个txt文件,在里面输入以下文字:net session /delete /y,并将其保存为clear session.bat文件.net session用于查看本机共享的会话详细情况,可以 ...

  6. VS2010编译Boost 1.56

    (1)首先下载源代码:http://softlayer-dal.dl.sourceforge.net/project/boost/boost/1.56.0/boost_1_56_0.zip 解压到某个 ...

  7. Jquery 数组操作(转)

    在jquery中处理JSON数组的情况中遍历用到的比较多,但是用添加移除这些好像不是太多. 今天试过json[i].remove(),json.remove(i)之后都不行,看网页的DOM对象中好像J ...

  8. k8s官方安装版本

    一.概述 官方安装链接:https://kubernetes.io/docs/getting-started-guides/kubeadm/ 之前使用是yum直接安装组件,现由kubeadm来自动安装 ...

  9. 会动的Tabbar

    项目搭建 一.设计模式首先呢,小Q采用传统的MVC的设计模式,优点我们再来啰嗦一下啊:1.多个视图可以对应一个模型.按MVC设计模式,一个模型对应多个视图,可以减少代码的复制及代码的维护量,一旦模型发 ...

  10. centos yum源

    #remi的源 rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm rpm --import /etc/pki/r ...