Enumerable#lazy
依赖于提供 #each
方法的枚举。如果您的可枚举对象没有 #each
方法,您就不能使用 #lazy
。现在 Kernel#enum_for
和 #to_enum
提供了指定枚举方法的灵 active ,而不是 #each
:
Kernel#enum_for(method = :each, *args)
但是 #enum_for
和 friend 们总是构建普通(非惰性)枚举器,而不是Enumerator::Lazy
。
我看到 Ruby 1.9.3 中的 Enumerator
提供了这种类似形式的#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
中弃用的构造函数。你怎么看?
最佳答案
我认为你应该使用 to_enum
返回一个普通的 Enumerator
:
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
这是大多数 rubyist 所期望的。尽管它是一个无限的 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
和其他几个方法将转发参数,以便立即可用。没有 block 的
Enumerator.new
消失了,因为to_enum
是应该使用的。请注意, block 形式仍然存在。还有一个用于Lazy
的构造函数,但它意味着从现有的Enumerable
开始。您声明
to_enum
永远不会创建惰性枚举器,但这并不完全正确。Enumerator::Lazy#to_enum
专门用于返回惰性枚举器。Enumerable
上调用to_enum
的任何用户方法都会使惰性枚举器保持惰性。
关于ruby - 当您的类未定义#each 时,返回 Enumerator::Lazy 的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15961453/