《Lua程序设计》9.3 以协同程序实现迭代器 学习笔记

例:编写一个迭代器,使其可以遍历某个数组的所有排列组合形式。代码如下:

function permgen(a, n)
    n = n or #a         -- 默认n为a的大小
    if n <= 1 then      -- 还需要改变吗?
        printResult(a)
    else
        for i=1,n do
            -- 将第一个元素放到数组末尾
            a[n], a[i] = a[i], a[n]
            -- 生成其余元素的排列
            permgen(a, n-1)
            -- 恢复第i个元素
            a[n], a[i] = a[i], a[n]
        end
    end
end

然后,还需要定义其中调用到的打印函数printResult,并以适当的参数来调用permgen:

function printResult (a)
    for i=1,#a do
        io.write(a[i], " ")
    end
    io.write("\n")
end

permgen ({1,2,3,4})

输出如下:

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 <= 1 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所创建的协同程序的状态,此外,也无法检测出运行时的错误。

时间: 2024-10-17 05:27:39

《Lua程序设计》9.3 以协同程序实现迭代器 学习笔记的相关文章

《Lua程序设计》9.1 协同程序基础 学习笔记

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

chapter9_3 协同程序实现迭代器

将循环迭代器视为"生产者-消费者"模式的一种特例:迭代器产生的数据供循环体消费. 因此,用协同程序写迭代器就理所当然了.因为协同程序可以一改传统调用者与被调用者之间的关系. 有了这个特性,在写迭代器时就无须顾及如何在每次成功的迭代调用间保持状态了. function permgen(a,n) n = n or #a --默认的n是数组a的大小 if n <= 1 then --只有一个元素,不需要排列 printresult(a) else for i = 1,n do a[n]

微信小程序开发:学习笔记[5]——JavaScript脚本

微信小程序开发:学习笔记[5]--JavaScript脚本 快速开始 介绍 小程序的主要开发语言是 JavaScript ,开发者使用 JavaScript 来开发业务逻辑以及调用小程序的 API 来完成业务需求. 在大部分开发者看来,ECMAScript和JavaScript表达的是同一种含义,但是严格的说,两者的意义是不同的.ECMAScript是一种由Ecma国际通过ECMA-262标准化的脚本程序设计语言, JavaScript 是 ECMAScript 的一种实现.理解 JavaScr

黑马程序员_OC学习笔记之Foundation框架集合类

OC--集合类 1.OC集合类包括NSArray,NSSet,NSDictionary都是以面向对象的方式操作数组,而且OC数组不像C语言中的数组只能存放同一种数据类型,它可以存放任意类型的对象,但是不能存放非OC对象类型如基本数据类型int,struct,enum等 2.OC数组是以对象的方式存在,因此在创建的时候需要为创建的对象前面加* 3.NSArray数组一旦创建就决定了是不是可变,而且永远是可变或不可变 4.NSArray数组和子类NSMutableArray的基本操作: 1>使用NS

黑马程序员_OC学习笔记之description方法和sel

OC--description方法 1.Description方法包括类方法和对象方法.(NSObject类所包含) -description(对象方法) 2.使用NSLog和@%输出某个对象时,会调用对象的description方法,并拿到返回值进行输出. +description(类方法) 3.使用NSLog和@%输出某个对象时,会调用类对象的description方法,并拿到返回值进行输出,把整个对象一次性打印出来,打印对象使用%@. 4.使用@%打印对象如(“@%”,P)默认打印输出为<

黑马程序员_OC学习笔记之@property和@synthesize

[objc] view plaincopyprint? <span style="font-size:24px;">#import <Foundation/Foundation.h> @interface Person : NSObject { int _age; int age; int _height; int height; int _weight; int weight; int _money; int money; } @property int ag

黑马程序员——Foundation学习笔记(NSSet和NSMutableSet)

==========android培训.ios培训.java培训.期待与您交流========== 一.NSSet: NSSet NSSet里面存储的元素没有顺序,NSArray中的元素有顺序. NSSet *s = [NSSet set]; // 创建一个空的Set,永远是空,不可变. NSSet *s2 = [NSSet setWithObjects:@"jack",@"rose",nil]; NSString *str = [s2 anyObject]; //

黑马程序员-OC学习笔记之Foundation框架NSNumber、NSValue和NSDate

---------------------- IOS开发.Android培训.期待与您交流! ---------------------- 一.NSNumber 前几篇笔记中,小桥复习了Foundatio框架中的几个类,这三个是OC学习的尾声了. 小桥已经复习过OC数组类NSArray,也说过它只能存放OC的对象,对于基本的数据类型确无能为力,但是实际编程中经常要把基本的数据如int.float,结构体存放的OC数组中,怎么办?这里的NSNumber就有用了,它能够把基本数据类型包装成OC对象.

黑马程序员-OC学习笔记之block

过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9426    Accepted Submission(s): 4151 Problem Description RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做par