<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    Ruby Fiber指南(四)迭代器

    Posted on 2010-03-12 12:48 dennis 閱讀(3279) 評論(0)  編輯  收藏 所屬分類: 動態(tài)語言 、my open-source

        Ruby Fiber指南(一)基礎(chǔ)
        Ruby Fiber指南(二)參數(shù)傳遞
        Ruby Fiber指南(三)過濾器
        Ruby Fiber指南(四)迭代器
        Ruby Actor指南(五)實現(xiàn)Actor

         上一節(jié)介紹了利用Fiber實現(xiàn)類unix管道風(fēng)格的過濾鏈,這一節(jié)將介紹利用Fiber來實現(xiàn)迭代器,我們可以將循環(huán)的迭代器看作生產(chǎn)者-消費者模式的特殊的例子。迭代函數(shù)產(chǎn)生值給循環(huán)體消費。所以可以使用Fiber來實現(xiàn)迭代器。協(xié)程的一個關(guān)鍵特征是它可以不斷顛倒調(diào)用者與被調(diào)用者之間的關(guān)系,這樣我們毫無顧慮的使用它實現(xiàn)一個迭代器,而不用保存迭代函數(shù)返回的狀態(tài),也就是說無需在迭代函數(shù)中保存狀態(tài),狀態(tài)的保存和恢復(fù)交由Fiber自動管理。

         這一節(jié)的介紹以一個例子貫穿前后,我們將不斷演化這個例子,直到得到一個比較優(yōu)雅的可重用的代碼,這個例子就是求數(shù)組的全排列。如數(shù)組[1,2,3]的全排列包括6種排列:
    2 3 1
    3 2 1
    3 1 2
    1 3 2
    2 1 3
    1 2 3
    全排列的遞歸算法實現(xiàn)很簡單,我們用Ruby實現(xiàn)如下:

    #全排列的遞歸實現(xiàn)
    def permgen (a, n)
        
    if n == 0 then
           printResult(a)
        
    else
            n.times do 
    |i|
               a[n
    -1], a[i] = a[i], a[n-1]
               permgen(a, n 
    - 1)
               a[n
    -1], a[i] = a[i], a[n-1]
           end
        end
    end

    def printResult (a)
        puts a.join(
    " ")
    end

    permgen([
    1,2,3,4],4)
    算法的思路是這樣:
    將數(shù)組中的每一個元素放到最后,依次遞歸生成所有剩余元素的排列,沒完成一個排列就打印出來。很顯然,這里有消費者和生產(chǎn)者的關(guān)系存在,生產(chǎn)者負(fù)責(zé)產(chǎn)生排列,消費者負(fù)責(zé)打印任務(wù),整個程序由消費者驅(qū)動,因此用Fiber改寫如下:

    第一步,將打印任務(wù)修改為Fiber#yield,生產(chǎn)者產(chǎn)生一個排列后將結(jié)果傳遞給消費者并讓出執(zhí)行權(quán):
    def permgen (a, n)
        
    if n == 0 then
           Fiber.
    yield(a)
        ……
    end

    第二步,實現(xiàn)一個迭代器工廠,返回一個匿名的迭代函數(shù),迭代函數(shù)請求Fiber產(chǎn)生一個新的排列:
    def perm(a)
      f
    =Fiber.new do
            permgen(a,a.size)
        end
      
    return lambda{ f.resume if f.alive? }
    end

    這樣一來我們就可以利用一個while循環(huán)來打印全排列:
    it=perm([1,2,3,4])

    while a=it.call
       printResult(a)
    end

        注意到,在perm方法中有一個很常見的模式,就是將對Fiber的resume封裝在一個匿名函數(shù)內(nèi),在lua為了支持這種模式還特意提供了一個coroutine.wrap方法來方便編程,在Ruby Fiber中卻沒有,不過我們可以自己實現(xiàn)下,利用open-class的特性實現(xiàn)起來非常簡單:
    #為Fiber添加wrap方法
    class Fiber
      
    def self.wrap
        
    if block_given?
          f
    =Fiber.new do |*args|
             
    yield *args
          end
          
    return lambda{|*args| f.resume(*args) if f.alive? }
        end
      end
    end
     
        Fiber#wrap方法跟new方法一樣,創(chuàng)建一個新的Fiber,但是返回的是一個匿名函數(shù),這個匿名函數(shù)負(fù)責(zé)去調(diào)用fiber的resume,利用wrap改寫perm方法變得更簡潔:
    def perm(a)
      Fiber.wrap{ permgen(a,a.size) }
    end

        但是還不夠,while循環(huán)的方式還是不夠優(yōu)雅,每次都需要明確地調(diào)用迭代器的call方法,這一點讓人挺不舒坦,如果能像for...in那樣的泛型循環(huán)就好了,我們知道Ruby中的for...in其實是一個語法糖衣,都是轉(zhuǎn)變成調(diào)用集合的each方法并傳入處理的block,因此,要想實現(xiàn)一個優(yōu)雅的迭代器,我們做下封裝就好了:

    class FiberIterator
      
    def initialize
        @fiber_wrap
    =Fiber.wrap do
            
    yield
        end
      end
      
    def each
        
    while value=@fiber_wrap.call
          
    yield value
        end
      end
    end

    那么現(xiàn)在的perm方法變成了創(chuàng)建一個迭代器FiberIterator:
    def perm(a)
      FiberIterator.new{ permgen(a,a.size) }
    end
    這樣一來我們就可以通過for...in來調(diào)用迭代器了

    it=perm([1,2,3,4])
    for a in it
      printResult(a)
    end


       

        
    主站蜘蛛池模板: 一级毛片在播放免费| 亚洲国产综合精品一区在线播放| 国产99久久久久久免费看| 2020年亚洲天天爽天天噜| 亚洲精品tv久久久久久久久 | 国产日产亚洲系列| 黑人粗长大战亚洲女2021国产精品成人免费视频| 中文字幕在线视频免费观看| 国产成人+综合亚洲+天堂| 亚洲三级中文字幕| 久久精品国产亚洲av麻豆小说| 亚洲欧洲美洲无码精品VA| 久久99亚洲综合精品首页 | 亚洲av无码成人精品国产| 精品亚洲成A人无码成A在线观看| 久久国产精品亚洲综合| 国产亚洲精品激情都市| 夜色阁亚洲一区二区三区| 性做久久久久免费看| 白白国产永久免费视频| 岛国片在线免费观看| 中文字幕av无码无卡免费| AV大片在线无码永久免费| 久久久久久精品免费看SSS| 无码av免费网站| 精品无码国产污污污免费网站 | 亚洲AV日韩AV高潮无码专区| 国产偷v国产偷v亚洲高清| 亚洲区小说区图片区QVOD| 久久国产亚洲精品麻豆| 亚洲人成在线播放网站| 亚洲欭美日韩颜射在线二| 亚洲夜夜欢A∨一区二区三区| 亚洲无人区午夜福利码高清完整版 | 亚洲精品成人片在线播放| 亚洲va无码专区国产乱码| 亚洲AV无码一区二区三区系列 | 二个人看的www免费视频| 免费无码av片在线观看| 在线成人精品国产区免费| 午夜不卡久久精品无码免费|