5

Enumerable#lazy#eachメソッドを提供する列挙型に依存しています。列挙型に#eachメソッドがない場合は、使用できません#lazy。以外の列挙方法を柔軟に指定できるようになりKernel#enum_forました。#to_enum#each

Kernel#enum_for(method = :each, *args)

しかし#enum_for、友人は常に単純な (遅延のない) 列挙子を作成し、決してEnumerator::Lazy.

EnumeratorRuby 1.9.3 では、このような形式の #new が提供されていることがわかります。

Enumerator#new(obj, method = :each, *args)

残念ながら、そのコンストラクターは Ruby 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。どう思いますか?

4

1 に答える 1

7

Enumeratorを使用して通常を返す必要があると思いますto_enum

class Calendar
  # ...
  def each_from(first)
    return to_enum(:each_from, first) unless block_given?
    loop do
      yield first if include?(first)
      first += step
    end
  end
end

これはほとんどのルビストが期待するものです。それは無限Enumerableですが、それでも使用できます。次に例を示します。

Calendar.new.each_from(1.year.from_now).first(10) # => [...first ten dates...]

実際に遅延列挙子が必要な場合は、lazy自分自身を呼び出すことができます。

Calendar.new.each_from(1.year.from_now)
  .lazy
  .map{...}
  .take_while{...}

遅延列挙子を本当に返したい場合は、lazyメソッドから呼び出すことができます。

  # ...
  def each_from(first)
    return to_enum(:each_from, first).lazy unless block_given?
    #...

ただし、予想外(IMO)であり、やり過ぎであり、パフォーマンスが低下する可能性があるため、お勧めしません。

最後に、あなたの質問にはいくつかの誤解があります。

  • だけでなく、をEnumerable想定するすべてのメソッド。eachlazy

  • 必要に応じてパラメーターを必要とするメソッドを定義して、eachを含めることができますEnumerable。のほとんどのメソッドはEnumerable機能しませんがeach_with_index、他のいくつかのメソッドは引数を転送するため、これらはすぐに使用できます。

  • 使用する必要がEnumerator.newあるため、ブロックなしはなくなりましたto_enum。ブロック形式が残ることに注意してください。のコンストラクタもありますがLazy、既存の から開始することを意図していEnumerableます。

  • あなたto_enumは怠惰な列挙子を決して作成しないと述べていますが、それは完全に真実ではありません。Enumerator::Lazy#to_enum遅延列挙子を返すように特化されています。Enumerableその呼び出しのユーザー メソッドはto_enum、遅延列挙子を遅延状態に保ちます。

于 2013-04-12T01:37:14.077 に答える