《Lua程序设计》9.3 以协同程序实现迭代器 学习笔记
例:编写一个迭代器,使其可以遍历某个数组的所有排列组合形式。代码如下:
function permgen(a, n)
n = n or #a -- 默认n为a的大小
if n <= then -- 还需要改变吗?
printResult(a)
else
for i=,n do
-- 将第一个元素放到数组末尾
a[n], a[i] = a[i], a[n]
-- 生成其余元素的排列
permgen(a, n-)
-- 恢复第i个元素
a[n], a[i] = a[i], a[n]
end
end
end
然后,还需要定义其中调用到的打印函数printResult,并以适当的参数来调用permgen:
function printResult (a)
for i=,#a do
io.write(a[i], " ")
end
io.write("\n")
end permgen ({,,,})
输出如下:
2 3 4 1
3 2 4 1
3 4 2 1
4 3 2 1
2 4 3 1
4 2 3 1
4 3 1 2
3 4 1 2
3 1 4 2
1 3 4 2
4 1 3 2
1 4 3 2
2 4 1 3
4 2 1 3
4 1 2 3
1 4 2 3
2 1 4 3
1 2 4 3
2 3 1 4
3 2 1 4
3 1 2 4
1 3 2 4
2 1 3 4
1 2 3 4
当生成函数完成后,将其转换为一个迭代器就非常容易了。首先,将printResult改为yield:
function permgen (a, n)
n - n or #a
if n <= then
coroutine.yield(a)
else
<as before>
然后,定义一个工厂方法,用于将生成函数放到一个协同程序中运行,并创建迭代器函数。迭代器指示简单地唤醒协同程序,让其产生下一种排列:
function permutations (a)
local co = coroutine.create(function () permgen(a) end)
return function () -- 迭代器
local code, res = coroutine.resume(co)
return res
end
end
有了上面的函数,在for语句中遍历一个数组中的所有排列就非常简单了:
for p in permutations {"a", "b", "c"} do
printResult(p)
end
--> b c a
--> c b a
--> c a b
--> b a c
--> a b c
permutations函数使用了一种在Lua中比较常见的模式,就是将一条唤醒协同程序的调用包装在一个函数中。由于这种模式比较常见,所以Lua专门提供了一个函数coroutine.wrap来完成这个功能。类似于create,wrap创建了一个新的协同程序。但不同的是,wrap并不是返回协同程序本身,而是返回一个函数。每当调用这个函数,即可唤醒一次协同程序。但这个函数与resume的不同之处在于,它不会返回错误代码。当遇到错误时,它会引发错误。若使用wrap,可以这么写permutations:
function permutations (a)
return coroutine.wrap(function () permgen(a) end)
end
通常,coroutine.wrap比couroutine.create更易于使用。它提供了一个对于协同程序编程实际所需的功能,即一个可以唤醒协同程序的函数。但也缺乏灵活性。无法检查wrap所创建的协同程序的状态,此外,也无法检测出运行时的错误。
《Lua程序设计》9.3 以协同程序实现迭代器 学习笔记的更多相关文章
- 《Lua程序设计》9.1 协同程序基础 学习笔记
协同程序(coroutine)与线程(thread)差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和指令指针,同时又与其他协同程序共享全局变量和其他大部分东西.从概念上讲线程与协同程序的主要区 ...
- 《Lua程序设计》第2章 类型与值 学习笔记
Lua中的8中基础类型:nil(空).boolean(布尔).number(数字).string(字符串).userdata(自定义类型).function(函数).thread(线程)和table( ...
- chapter9_3 协同程序实现迭代器
将循环迭代器视为"生产者-消费者"模式的一种特例:迭代器产生的数据供循环体消费. 因此,用协同程序写迭代器就理所当然了.因为协同程序可以一改传统调用者与被调用者之间的关系. 有了这 ...
- 微信小程序开发:学习笔记[5]——JavaScript脚本
微信小程序开发:学习笔记[5]——JavaScript脚本 快速开始 介绍 小程序的主要开发语言是 JavaScript ,开发者使用 JavaScript 来开发业务逻辑以及调用小程序的 API 来 ...
- 微信小程序开发:学习笔记[7]——理解小程序的宿主环境
微信小程序开发:学习笔记[7]——理解小程序的宿主环境 渲染层与逻辑层 小程序的运行环境分成渲染层和逻辑层. 程序构造器
- 微信小程序开发:学习笔记[4]——样式布局
微信小程序开发:学习笔记[4]——样式布局 Flex布局 新的布局方式 在小程序开发中,我们需要考虑各种尺寸终端设备上的适配.在传统网页开发,我们用的是盒模型,通过display:inline | b ...
- 微信小程序开发:学习笔记[3]——WXSS样式
微信小程序开发:学习笔记[3]——WXSS样式 快速开始 介绍 WXSS(WeiXin Style Sheets)是一套用于小程序的样式语言,用于描述WXML的组件样式,也就是视觉上的效果. WXSS ...
- 微信小程序开发:学习笔记[2]——WXML模板
微信小程序开发:学习笔记[2]——WXML模板 快速开始 介绍 WXML 全称是 WeiXin Markup Language,是小程序框架设计的一套标签语言,结合小程序的基础组件.事件系统,可以构建 ...
- 微信小程序开发:学习笔记[1]——Hello World
微信小程序开发:学习笔记[1]——Hello World 快速开始 1.前往微信公众平台下载微信开发者工具. 地址:https://mp.weixin.qq.com/debug/wxadoc/dev/ ...
随机推荐
- (笔记)Linux Root下的.gvfs出现异常解决办法
在linux系统下安装软件或复制文件的时候,复制不成功,出现错误如下: error: failed to stat /home/dade/.gvfs: Permission denied. 表面上看: ...
- "android.uid.systemandroid.view.InflateException: Binary XML file line #7: Error inflating class android.webkit.WebView
在android源码中编译app通过,运行时出现错误: "android.uid.systemandroid.view.InflateException: Binary XML file l ...
- Java如何显示小时和分钟?
在Java中,如何显示小时和分钟(当前时间)? 此示例演示如何使用Calender类的Calender.getInstance()来显示某个时刻的小时和分钟. package com.yiibai; ...
- mysql limit分页查询效率
对于有大数据量的mysql表来说,使用LIMIT分页存在很严重的性能问题. 查询从第1000000之后的30条记录: SQL代码1:平均用时6.6秒 SELECT * FROM `cdb_posts` ...
- Aspose.Words对于Word的操作
对于word操作一般是对已有word模板的操作,直接新建的不考虑,网上教程很多,自己看吧一般有以下几种办法(忘了具体几种了,一般情况下以下就够了)1.通过书签替换顾名思义,就是先定义一个书签,然后在书 ...
- Oracle EM错误,java.lang.Exception: Exception in sending Request :: null 分类: Oracle 2015-07-08 21:24 44人阅读 评论(0) 收藏
操作系统:Win7 64bit Oracle: 10.2.0.1.0 很久没有使用EM了,打开一看,居然报错了,出现java.lang.Exception: Exception in sending ...
- .net framework 4.0上跑webapi 1.0
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web AP ...
- Making ARC and non-ARC files play nice together
From Codeography If you want to exclude a file from being compiled with ARC you can do so by setting ...
- UNIX环境编程学习笔记(2)——文件I/O之不带缓冲的 I/O
lienhua342014-08-25 1 文件描述符 对于内核而言,所有打开的文件都通过文件描述符引用.文件描述符是一个非负整数.当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符. ...
- C++中使用ODBC API访问数据库例程
使用ODBC API访问数据库简单流程,供参考使用: ODBC API 123456789101112131415161718192021222324252627282930313233343536 ...