Ruby Fiber指南(四)迭代器

2021-09-23 16:45:56 字數 2690 閱讀 4498

ruby fiber指南(一)基礎

ruby fiber指南(二)引數傳遞

ruby fiber指南(三)過濾器

ruby fiber指南(四)迭代器

ruby actor指南(五)實現actor

上一節介紹了利用fiber實現類unix管道風格的過濾鏈,這一節將介紹利用fiber來實現迭代器,

我們可以將迴圈的迭代器看作生產者

- 消費者模式的特殊的例子。迭代函式產生值給迴圈體消費。所以可以使用fiber來實現迭代器。協程的乙個關鍵特徵是它可以不斷顛倒呼叫者與被呼叫者之間的關係,這樣我們毫無顧慮的使用它實現乙個迭代器,而不用儲存迭代函式返回的狀態,也就是說無需在迭代函式中儲存狀態,狀態的儲存和恢復交由fiber自動管理。

這一節的介紹以乙個例子貫穿前後,我們將不斷演化這個例子,直到得到乙個比較優雅的可重用的**,這個例子就是求陣列的全排列。如陣列[1,2,3]的全排列包括6種排列:23

1321

3121

3221

3123

全排列的遞迴演算法實現很簡單,我們用ruby實現如下: #

全排列的遞迴實現

defpermgen (a, n)

ifn 

==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

endend

defprintresult (a)

puts a.join(""

)end

permgen([1,

2,3,

4],4)

演算法的思路是這樣:

將陣列中的每乙個元素放到最後,依次遞迴生成所有剩餘元素的排列,沒完成乙個排列就列印出來。很顯然,這裡有消費者和生產者的關係存在,生產者負責產生排列,消費者負責列印任務,整個程式由消費者驅動,因此用fiber改寫如下:

第一步,將列印任務修改為fiber#yield,生產者產生乙個排列後將結果傳遞給消費者並讓出執行權:

defpermgen (a, n)

ifn 

==0 then

fiber.

yield

(a)……

end

第二步,實現乙個迭代器工廠,返回乙個匿名的迭代函式,迭代函式請求fiber產生乙個新的排列:

defperm(a)f=

fiber.new do

permgen(a,a.size)

endreturn

lambda

end

這樣一來我們就可以利用乙個while迴圈來列印全排列: it

=perm([1,

2,3,

4])whilea=

it.call

printresult(a)

end

注意到,在perm方法中有乙個很常見的模式,就是將對fiber的resume封裝在乙個匿名函式內,在lua為了支援這種模式還特意提供了乙個coroutine.wrap方法來方便程式設計,在ruby fiber中卻沒有,不過我們可以自己實現下,利用open-class的特性實現起來非常簡單: #

為fiber新增wrap方法

class

fiber

defself.wrap

ifblock_given?f=

fiber.new do 

|*args

|yield

*args

endreturn

lambda

endend

end  

fiber#wrap方法跟new方法一樣,建立乙個新的fiber,但是返回的是乙個匿名函式,這個匿名函式負責去呼叫fiber的resume,利用wrap改寫perm方法變得更簡潔:

defperm(a)

fiber.wrap

end

但是還不夠,while迴圈的方式還是不夠優雅,每次都需要明確地呼叫迭代器的call方法,這一點讓人挺不舒坦,如果能像for...in那樣的泛型迴圈就好了,我們知道ruby中的for...in其實是乙個語法糖衣,都是轉變成呼叫集合的each方法並傳入處理的block,因此,要想實現乙個優雅的迭代器,我們做下封裝就好了:

class

fiberiterator

definitialize

@fiber_wrap

=fiber.wrap do

yield

endend

defeach

while

value

=@fiber_wrap.call

yield

value

endend

end

那麼現在的perm方法變成了建立乙個迭代器fiberiterator:

defperm(a)

fiberiterator.new

end 這樣一來我們就可以通過for...in來呼叫迭代器了 it

=perm([1,

2,3,

4])fora 

init

printresult(a)

end

文章**莊周夢蝶  ,原文發布時間 2010-03-12 

迭代器程式設計指南

c 程式設計指南 迭代器 c 程式設計指南 迭代器是一種方法 get 訪問器或運算子,它通過使用 yield 關鍵字對陣列或集合類執行自定義迭代。yield返回語句會導致源序列中的元素在訪問源序列中的下乙個元素之前立即返回給呼叫方。儘管您以方法的形式編寫迭代器,但編譯器會將其轉換為乙個實際上是狀態機...

Python函式式程式設計指南(三) 迭代器

python generators 生成器 生成器是這樣乙個函式,它記住上一次返回時在函式體中的位置。對生成器函式的第二次 或第 n 次 呼叫跳轉至該函式中間,而上次呼叫的所有區域性變數都保持不變。生成器不僅 記住 了它資料狀態 生成器還 記住 了它在流控制構造 在命令式程式設計中,這種構造不只是資...

迭代器 反向迭代器

c primer 中文版第四版 第273頁 9.3.2 begin和end成員 begin和end操作產生指向容器內第乙個元素和最後乙個元素的下乙個位置的迭代器,如下所示。這兩個迭代器通常用於標記包含容器中所有元素的迭代範圍。c.begin 返回乙個迭代器,它指向容器c的第乙個元素 c.end 返回...