Dig это, вот это круто Enumerator
(ленивая последовательности) от 1 до (самый большого Float
рубин может представлять собой):почему Enumerator включает Enumerable
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
) получил свой #drop
метод из (модуля) Enumerable
смешивает с Enumerator
(класса). Теперь почему в мире Ruby пойдет и смешат Enumerable
в Enumerator
вы спросите? Я не знаю. Но там это, задокументировано как в Enumerator
in Ruby 1.9.3, так и в Enumerator
in Ruby 2.0.
Проблема, поскольку я вижу, что некоторые методы, определенные в Enumerable
, работают или вид работы на Enumerator
. Примеры включают #first
и #take
. По крайней мере один другой: #drop
не работает.
Мне кажется, что Enumerator
включая Enumerable
является ошибкой. Как вы думаете?
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>
Обратите внимание, что 'каждый' в' e = (1..Float :: INFINITY) .each' не имеет значения. Вы должны либо оставить его, либо заменить его «ленивым», в зависимости от того, что вы хотите точно. –
Спасибо, Марк-Андре. Но в Ruby 1.9.3 нет перечислимого # lazy. Это доступно только в версии 2.0. Я думаю, что одно из моих ключевых недоразумений заключалось в том, что #drop возвратил Enumerator вообще. По какой-то причине, хотя и #drop и #take имеют тривиальные реализации Enumerator, ни один из них не возвращает Enumerator! Даже исправление для [Ruby Bug # 7715 «Lazy enumerators» должно хотеть оставаться ленивым »] (https://bugs.ruby-lang.org/issues/7715) не удалось их исправить. Подумайте об этом, они не могут быть «исправлены», так как это приведет к слому кода, который опирается на возвращающиеся массивы! –
Действительно, 'drop' является« нетерпеливым ». BTW, вы можете играть с 'lazy' в любой версии Ruby с' require 'backports/2.0.0/enumerable/lazy'' –