Enumerable#lazy
полагается на ваш счетчик, предоставляя метод #each
. Если ваш счетчик не имеет метода #each
, вы не можете использовать #lazy
. Теперь Kernel#enum_for
и #to_enum
обеспечивают гибкость, чтобы указать способ перечисления, кроме #each
:Какой лучший способ вернуть Enumerator :: Lazy, когда ваш класс не определяет #each?
Kernel#enum_for(method = :each, *args)
Но #enum_for
и друзья всегда строить простые (без ленивых) счетчиков, никогда Enumerator::Lazy
.
Я вижу, что Enumerator
в Руби 1.9.3 предлагает эту подобную форму #new:
Enumerator#new(obj, method = :each, *args)
К сожалению, этот конструктор был полностью удален в Рубине 2.0. Также я не думаю, что он был вообще доступен на Enumerator::Lazy
. Так что мне кажется, что если у меня есть класс с методом, я хочу вернуть ленивый перечислитель, если у этого класса нет #each
, тогда я должен определить некоторый вспомогательный класс, который определяет #each
.
Например, у меня есть класс Calendar
. Для меня не имеет смысла предлагать перечислять каждую дату с начала всего времени. #each
было бы бесполезно. Вместо этого я предлагаю метод, который перечисляет (лениво) от начальной даты:
class Calendar
...
def each_from(first)
if block_given?
loop do
yield first if include?(first)
first += step
end
else
EachFrom.new(self, first).lazy
end
end
end
И что EachFrom
класса выглядит следующим образом:
class EachFrom
include Enumerable
def initialize(cal, first)
@cal = cal
@first = first
end
def each
@cal.each_from(@first) do |yielder, *vals|
yield yielder, *vals
end
end
end
Это работает, но он чувствует себя тяжелым. Может быть, я должен был подклассифицировать Enumerator::Lazy
и определить такой конструктор, который устарел от Enumerator
. Как вы думаете?
Вы просто взорвали мой ум Марк-Андре. Мой код просто перешел от идиотического к идиоматическому. Я не понимал, что Ruby хочет, чтобы мы всегда трафик в Enumerators, а не Enumerator :: Lazy. Где нам нужно что-то быть ленивым, мы просим перечислителя для #lazy версии. Недостатком, возможно, является то, что пользователи наших абстракций действительно должны понимать, когда звонить #lazy (например, перед вызовом #drop (n)). Поверхность - четкий чистый код. –
У меня было так много проблем (и многому чему научился) #drop (n). Теперь, когда я возвращаю «простые» счетчики всюду, мне пришлось побрызгать несколько ... lazy.drop (n) ... о. Поэтому я определил метод, похожий на капли, который просто продвигает Enumerator, позволяя мне изменить его на ... skip (n) ... –
Право. Вы можете определенно определить такой метод, как 'Enumerable # skip (n)', который возвратил бы 'Enumerator' вместо массива типа' drop' и сыграл бы с этим. –