5

Enumerable#lazy依赖于您提供的可枚举#each方法。如果您的可枚举没有#each您不能使用的方法#lazy。现在Kernel#enum_for#to_enum提供指定除以下以外的枚举方法的灵活性#each

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

但是#enum_for和朋友们总是构造普通(非惰性)枚举器,从不Enumerator::Lazy

我看到Enumerator在 Ruby 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假设的所有方法each,而不仅仅是lazy

  • 您可以定义一个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 回答