[英]why does Enumerator include Enumerable
挖掘一下,這是一個很酷的Enumerator
(惰性序列),從1到(最大的Float
Ruby可以代表):
1.9.3-p327 :014 > e = (1..Float::INFINITY).each
看一下如何抓住序列的前面:
1.9.3-p327 :015 > e.first
=> 1
1.9.3-p327 :016 > e.take(2)
=> [1, 2]
那是好東西吧? 我也這么認為。 但是然后這樣:
1.9.3-p327 :017 > e.drop(2).first
進入拉拉土地。 我的意思是它不會在不到5秒的時間內返回。
哦,這是一個線索:
1.9.3-p327 :020 > p e.method(:drop)
#<Method: Enumerator(Enumerable)#drop>
似乎Enumerator( e
)從Enumerable
(模塊)混合到Enumerator
(類)中獲得了其#drop
方法。 現在為什么在世界上Ruby會把您要求的Enumerable
混合到Enumerator
? 我不知道。 但是,它是,在這兩個文件Enumerator
在Ruby中1.9.3和Enumerator
的紅寶石2.0 。
我看到的問題是Enumerable
工作中定義的某些方法或Enumerator
上的某種工作。 示例包括#first
和#take
。 至少有一個: #drop
不起作用。
在我看來,包括Enumerable
Enumerator
是一個錯誤。 你怎么看?
PS注意到Ruby 2.0定義了Enumerator::Lazy
( Enumerator
子類),它總是定義一堆Enumerable
方法。 這里有些腥味。 為什么在不懶惰,在某些情況下,破碎的方法(成混合Enumerator
)只是轉身和提供(子類懶替代Enumerator
)?
也可以看看:
1.9.3-p327 :018 > p e.method(:first)
#<Method: Enumerator(Enumerable)#first>
1.9.3-p327 :020 > p e.method(:drop)
#<Method: Enumerator(Enumerable)#drop>
這是許多其他收集框架所共有的設計選擇。
Ruby的收集操作不保留類型。 他們總是返回Array
,無論調用了什么類型的集合。 例如,.NET也是如此,除了那里的類型始終是IEnumerable
,它既更有用(因為可以將更多內容表示為IEnumerable
不是Array
,例如無限序列),但同時卻不那么有用(因為IEnumerable
的接口比Array
的接口小得多,所以您可以對其進行較少的操作)。
這使得Ruby的收集操作可以一次實現,而無需重復。
這也意味着將您自己的集合集成到Ruby的集合框架中非常容易:只需實現each
,mixin Enumerable
即可完成。 如果將來的Ruby版本添加了新的收集方法(例如Ruby 1.9中的flat_map
),則您無需執行任何操作 ,它也可以與您的收集一起使用。
另一個設計選擇是使所有收集操作保持類型。 因此,所有收集操作都返回它們被調用的類型。
有一些語言可以做到這一點。 但是,它是通過將所有收集方法復制並粘貼到所有收集類中來實現的,即具有大量代碼復制功能。
這意味着,如果您想將自己的集合添加到集合框架中,則必須實現集合協議的每個方法。 而且,如果該語言的未來版本添加了新方法,則您必須發布集合的新版本。
Scala 2.8的收集框架是第一次有人弄清楚如何在不重復代碼的情況下進行類型保留的收集操作。 但這是在設計了Ruby的收集框架之后很長時間的。 在設計Ruby的收集框架時,還不知道如何在不進行代碼重復的情況下進行類型保留的收集操作,因此Ruby的設計者選擇了不進行重復。
從Ruby 1.9開始,實際上存在一些重復。 復制了一些Hash
方法以返回Hash
而不是Array
。 而且您已經提到了Ruby 2.0的Enumerator::Lazy
,它復制了許多Enumerable
方法來返回Enumerator::Lazy
。
可以使用Scala在Ruby中使用的相同技巧,但是這需要對收集框架進行徹底的修改,這將使每個現有的收集實現都過時。 Scala之所以能夠做到這一點,是因為當時幾乎沒有用戶群。
針對第一部分:
“進入拉拉土地。這意味着它不會在不到5秒的時間內返回。”
該行為似乎與這些方法應該執行的操作一致:
take(n) → array # Returns first n elements from enum.
這意味着您只需要迭代N即可返回它。
drop(n) → array # #Drops first n elements from enum, and returns rest elements in an array.
這意味着它需要其余元素才能返回它們。 而且由於您的上限是Float::INFINITY
因此它的行為也是如此。
來源: 可枚舉
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.