• 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],a[i] = a[i],a[n]    --把第i个元素放在最末尾
                permgen(a,n-1)           --用余下的元素产生排列
                a[n],a[i] = a[i],a[n]    --恢复第i个元素
            end
        end
    end

    permgen调用如下:

    function printResult(a)
        for i=1,#a do
            io.write(a[i]," ")
        end
        io.write("
    ")
    end
    
    permgen({1,2,3,4})
        --> 2 3 4 1
        --> 3 2 4 1
            ......
        -->1 2 3 4

    有了迭代器的generator函数,将它转换为一个迭代器就容易多了.

    首先将printResult改为yield:

    function permgen(a,n)
        n = n or #a
        if n <=1 then
            coroutine.yield(a)
        else
          for i = 1,n do
                a[n],a[i] = a[i],a[n]  --把第i个元素放在最末尾
                permgen(a,n-1)         --用余下的元素产生排列
                a[n],a[i] = a[i],a[n]  --恢复第i个元素
           end
      end
    end

    然后定义一个工厂函数,用于将generator函数放到一个协同程序中运行,并创建迭代器函数。

    迭代器只是简单地唤醒协同程序,让其产生下一种排列:

    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
        -->a c b
        -->b a c
        -->a b c

    permutations函数使用了一种Lua中比较常见的模式,就是将一条唤醒协同程序的调用包装在一个函数中。

    由于这种模式比较常见,Lua专门提供了一个函数coroutine.wrap来完成这个功能。

    类似于create,wrap创建了一个新的协同程序。但不同的是,wrap并不是返回协同程序本身,而是一个函数。

    每当调用这个函数,即可唤醒一次协同程序。但这个函数与resume的不同之处在于,它不会返回错误代码。

    当遇到错误时,它会引发错误。若使用wrap,可以这样写:

    function permutations(a)        --协同程序迭代器升级版
        return coroutine.wrap(function () permgen(a) end) 
    end

    wrap要比coroutine.create更容易使用。它提供了一个对于协同程序编程实际所需的功能:即一个可以唤醒协同程序的函数。

    但是缺乏灵活性,无法检查wrap所创建的协同程序的状态,此外,也无法检测出运行时的错误。

    和resume返回值相同,只是没有第一个布尔量。如果发生任何错误,抛出这个错误。

  • 相关阅读:
    python基础五——初识函数
    python基础三——基础数据类型
    Python基础二
    python基础一
    2.配置jenkins
    1.jenkins 安装
    Java8 新特性
    Java8 新特性
    1.什么是 Docker
    idea快捷键
  • 原文地址:https://www.cnblogs.com/daiker/p/5824161.html
Copyright © 2020-2023  润新知