Lua语法基础(3)--迭代器和泛型for
迭代器和闭包
迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。
迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是他知道来自于哪里和将要前往哪里。闭包提供的机制可以很容易实现这个任务。记住:闭包是一个内部函数,它可以访问一个或者多个外部函数的外部局部变量。每次闭包的成功调用后这些外部局部变量都保存他们的值(状态)。当然如果要创建一个闭包必须要创建其外部局部变量。所以一个典型的闭包的结构包含两个函数:一个是闭包自己;另一个是工厂(创建闭包的函数)。
举一个简单的例子,我们为一个list写一个简单的迭代器,与ipairs()不同的是我们实现的这个迭代器返回元素的值而不是索引下标:
- function list_iter (t)
- local i =
- local n = table.getn(t)
- return function ()
- i = i +
- if i <= n then return t[i] end
end- end
这个例子中list_iter是一个工厂,每次调用他都会创建一个新的闭包(迭代器本身)。闭包保存内部局部变量(t,i,n),因此每次调用他返回list中的下一个元素值,当list中没有值时,返回nil.我们可以在while语句中使用这个迭代器:
- t = {, , }
- iter = list_iter(t) -- creates the iterator
- while true do
- local element = iter() -- calls the iterator
- if element == nil then break end
- print(element)
- end
我们设计的这个迭代器也很容易用于范性for语句。
- t = {, , }
- for element in list_iter(t) do
- print(element)
- end
范性for为迭代循环处理所有的薄记(bookkeeping):首先调用迭代工厂;内部保留迭代函数,因此我们不需要iter变量;然后在每一个新的迭代处调用迭代器函数;当迭代器返回nil时循环结束。
范性for的语义
前面我们看到的迭代器有一个缺点:每次调用都需要创建一个闭包,大多数情况下这种做法都没什么问题,然而在有些情况下创建闭包的代价是不能忍受的。在这些情况下我们可以使用范性for本身来保存迭代的状态。
前面我们看到在循环过程中范性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;表达式列表pair(t)。
我们称变量列表中第一个变量为控制变量,其值为nil时循环结束。
下面我们看看范性for的执行过程:
首先,初始化,计算in后面表达式的值,表达式应该返回范性for需要的三个值:迭代函数,状态常量和控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略。
第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
第三,将迭代函数返回的值赋给变量列表。
第四,如果返回的第一个值为nil循环结束,否则执行循环体。
第五,回到第二步再次调用迭代函数。
更精确的来说:
- 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
如果我们的迭代函数是f,状态常量是s,控制变量的初始值是a0,那么控制变量将循环:a1=f(s,a0)、a2=f(s,a1)、⋯⋯,直到ai=nil。
无状态的迭代器
每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。这种无状态迭代器的典型的简单的例子是ipairs,他遍历数组的每一个元素。
- a = {"one", "two", "three"}
- for i, v in ipairs(a) do
- print(i, v)
- end
迭代的状态包括被遍历的表(循环过程中不会改变的状态常量)和当前的索引下标(控制变量),ipairs和迭代函数都很简单,我们在Lua中可以这样实现:
- function iter (a, i)
- i = i +
- local v = a[i]
- if v then
- return i, v
- end
- end
- function ipairs (a)
- return iter, a,
- 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。
开始的迭代函数很简单,必须返回迭代函数和初始状态。
- local iterator -- to be defined later
- function allwords()local state = {line = io.read(), pos = }
- return iterator, state
- end
真正的处理工作是在迭代函数内完成:
- function iterator (state)
- while state.line do --repeat while there are lines
- --search for next word
- local s,e = string.find(state.line,”%w+”,state.pos)
- if s then
- state.pos = e+
- return string.sub(state.line,s,e)
- else
- state.line = io.read()
- state.pos =
- end
- end
- return nil
- end
我们应该尽可能的写无状态的迭代器,因为这样循环的时候由 for 来保存状态,如果不能用无状态的迭代器实现,应尽可能适用闭包;尽可能不要适用table这种方式。
Lua语法基础(3)--迭代器和泛型for的更多相关文章
- Lua语法基础(1)---简介、基本数据类型、表达式
我觉得我已经陷入了一个坑内.因为,安装了Lua和SublimeText3编辑器之后,怎么使自己编写的lua代码在untiy内运行起来,是个我完全不了解的机制.先放一放吧.首先,来回顾一下Lua的语法基 ...
- Lua语法基础(一)
1. 注释 -- 单行注释 --[[ 多行注释 --]] 2. 运行方式 (1)交互式运行 命令行下 lua进入交互模式 (2)命令行运行 lua + ...
- Lua语法基础(2)--基本语法、函数
上一篇编辑编辑着,发现,缩进出了问题.作为一个不是强迫症的人,实在是忍受不了同一级内容不同缩进方式的槽点,于是重开一篇吧.(万幸,这样的文章也只有我自己看.) 第四 基本语法 赋值语句,Lua可以对多 ...
- lua语法 - 基础篇
1. 注释 单行注释:--,类似于C++的// 多行注释:--[[ ... ]],类似于C++的/*...*/ 2. 语句 分隔符:分号或者空格,一般多行写一起,建议用分号 语句块:do ... en ...
- Java语法基础学习DayTwelve(泛型)
一.泛型(Generic)在集合中的使用 1.作用 (1)解决元素存储的安全问题 (2)解决获取数据元素时,需要类型强转的问题 2.代码案例 //在集合没有使用泛型的情况下 List list = n ...
- python语法基础-函数-迭代器和生成器-长期维护
############### 迭代器 ############## """ 迭代器 这是一个新的知识点 我们学习过的可以迭代的对象有哪些? list str ...
- Lua语法基础(二)
1. 函数 1.1 函数声明 默认为全局 局部函数使用local关键字声明 1.2 参数 ...等同于Python中*args三个点表示可变参数 1.3 获取参数长度的两种方式 (1)将传入的参数.. ...
- Lua脚本之语法基础快速入门
要 1.基本数据类型 2.Lua中的常用语句结构以及函数 3.Lua中的常用语句结构介绍 4.Lua中的库函数 目录[-] 一.基本数据类型 二.Lua中的常用语句结构以及函数 1.Lua中的常用语句 ...
- Lua学习(5)——迭代器与泛型for
1. 迭代器 2. 泛型for语义 所谓迭代器就是一种可以遍历一种集合中所有元素的机制.在lua中,迭代器通常表示为函数,每调用依次函数就返回集合中的下一个元素.泛型for 内部保存了迭代器函数 实际 ...
随机推荐
- 关于js中的回调函数callback
来源于:http://www.jianshu.com/p/6bc353e5f7a3 前言 其实我一直很困惑关于js 中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制 ...
- Ubuntu常用命令大全[显示桌面]
Ubuntu常用命令大全 查看软件xxx安装内容 #dpkg -L xxx 查找软件 #apt-cache search 正则表达式 查找文件属于哪个包 #dpkg -S filename apt-f ...
- 【LeetCode】224. Basic Calculator
Basic Calculator Implement a basic calculator to evaluate a simple expression string. The expression ...
- 完善_IO, _IOR, _IOW, _IOWR 宏的用法与解析
_IO, _IOR, _IOW, _IOWR 宏的用法与解析 原文地址:http://www.eefocus.com/ayayayaya/blog/12-03/245777_20cdd.html 作 ...
- 简单解决XP共享连接数10限制(转)
1.建立一个txt文件,在里面输入以下文字:net session /delete /y,并将其保存为clear session.bat文件.net session用于查看本机共享的会话详细情况,可以 ...
- VS2010编译Boost 1.56
(1)首先下载源代码:http://softlayer-dal.dl.sourceforge.net/project/boost/boost/1.56.0/boost_1_56_0.zip 解压到某个 ...
- Jquery 数组操作(转)
在jquery中处理JSON数组的情况中遍历用到的比较多,但是用添加移除这些好像不是太多. 今天试过json[i].remove(),json.remove(i)之后都不行,看网页的DOM对象中好像J ...
- k8s官方安装版本
一.概述 官方安装链接:https://kubernetes.io/docs/getting-started-guides/kubeadm/ 之前使用是yum直接安装组件,现由kubeadm来自动安装 ...
- 会动的Tabbar
项目搭建 一.设计模式首先呢,小Q采用传统的MVC的设计模式,优点我们再来啰嗦一下啊:1.多个视图可以对应一个模型.按MVC设计模式,一个模型对应多个视图,可以减少代码的复制及代码的维护量,一旦模型发 ...
- centos yum源
#remi的源 rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm rpm --import /etc/pki/r ...