Enumerable#lazy
verlässt sich auf Ihre Enumerable Bereitstellung einer #each
Methode. Wenn Ihr Enumerable keine #each
Methode hat, können Sie #lazy
nicht verwenden. Jetzt Kernel#enum_for
und #to_enum
bieten die Flexibilität, eine Aufzählung andere Methode als #each
angeben:Was ist der beste Weg, um einen Enumerator :: Lazy zurückzugeben, wenn Ihre Klasse #each nicht definiert?
Kernel#enum_for(method = :each, *args)
Aber #enum_for
und Freunde immer konstruieren Ebene (nicht faul) Aufzählungen, nie Enumerator::Lazy
.
Ich sehe, dass Enumerator
in Ruby 1.9.3 diese ähnliche Form der #new bietet:
Enumerator#new(obj, method = :each, *args)
Leider, dass Konstruktor wurde in Ruby 2.0 vollständig entfernt. Ich glaube auch nicht, dass es jemals auf Enumerator::Lazy
überhaupt verfügbar war. So scheint es mir, dass, wenn ich eine Klasse mit einer Methode habe, ich einen Lazy Enumerator zurückgeben möchte, wenn diese Klasse keine #each
hat, dann muss ich eine Hilfsklasse definieren, die #each
definiert.
Zum Beispiel habe ich eine Calendar
Klasse. Es macht für mich wenig Sinn, jedes Datum von Anfang an aufzuzählen. Ein wäre nutzlos. Stattdessen biete ich eine Methode, die (träge) von einem Startdatum aufzählt:
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
Und das EachFrom
Klasse sieht wie folgt aus:
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
Es funktioniert, aber es fühlt sich schwer an. Vielleicht sollte ich die Unterklasse Enumerator::Lazy
ableiten und einen Konstruktor wie den veralteten von Enumerator
definieren. Was denken Sie?
Sie haben gerade meine Meinung Marc-André. Mein Code ging einfach von idiotisch zu idiomatisch. Ich habe nicht verstanden, dass Ruby möchte, dass wir immer mit Enumeratoren und nicht mit Enumerator :: Lazy handeln. Wo immer wir etwas brauchen, um faul zu sein, fragen wir diesen Enumerator für die Version #lazy. Der Nachteil ist vielleicht, dass Benutzer unserer Abstraktionen wirklich verstehen müssen, wann sie #lazy aufrufen müssen (z. B. bevor sie #drop (n) aufrufen). Die Oberseite ist sauberer sauberer Code. –
Ich hatte so viel Probleme mit (und lernte so viel) #drop (n). Jetzt, wo ich "normale" Aufzählungszeichen zurückgebe, musste ich überall ein paar ... faule.drop (n) ... herum streuen. Also habe ich eine Drop-ähnliche Methode definiert, die den Enumerator einfach weiterleitet und mir erlaubt, diese zu ... skip (n) zu ändern ... –
Richtig. Sie können definitiv eine Methode wie 'Enumerable # skip (n)' definieren, die anstelle eines Arrays wie 'drop' einen' Enumerator' zurückgibt und damit spielt. –