为什么Enumerable在Ruby中没有length属性?

至少在Ruby 1.9.3中, Enumerable对象没有length属性。

据我所知,任何Enumerable都是一个集合,如sortfind_index等方法所certificate。

一个集总是有一个定义明确的长度(……对吗?),为什么这不是一个属性?

Enumerable有count方法,它通常是枚举的直观“长度”。

但为什么不把它称为“长度”? 好吧,因为它的运作方式非常不同。 在Ruby的内置数据结构(如ArrayHashlength只检索数据结构的预先计算大小。 它应该总是立即返回。

但是,对于Enumerable#count ,它无法知道它正在运行什么类型的结构,因此没有快速,巧妙的方法来获取枚举的大小(这是因为Enumerable是一个模块,并且可以包含在任何模块中类)。 获取枚举大小的唯一方法是实际枚举它并按其计算。 对于无限枚举, count将(适当地)永远循环并且永不返回。

枚举不能保证有长度 – 对于Enumerable混合的对象的唯一要求是它响应#each ,导致它返回系列中的下一个项目, #<=>允许比较提供的值由可数。 像#sort这样的方法将在排序过程中枚举整个集合,但可能不会提前知道集合的边界。 考虑:

 class RandomSizeEnumerable include Enumerable def each value = rand 1000 while value != 500 yield value value = rand 1000 end end # Not needed for this example, but included as a part of the Enumerable "interface". # You only need this method if #max, #min, or #sort are used on this class. def <=>(a, b) a <=> b end end 

在迭代器生成值“500”之前,将调用此枚举,这将导致它停止枚举。 收集并排序结果集。 但是,在这种情况下, #length方法没有意义,因为在迭代器耗尽之前,长度是不可知的!

我们可以在#length之类的结果上调用#length ,因为它们返回一个数组,但是:

 p RandomSizeEnumerable.new.sort.length # 321 p RandomSizeEnumerable.new.sort.length # 227 p RandomSizeEnumerable.new.sort.length # 299 

通常,当长度已知并且可以在恒定时间内返回时使用#count ,而当提前知道长度并且需要通过迭代计算时,倾向于使用#count (有时是#size )。结果集(因此,采用线性时间)。 如果您需要Enumerable提供的结果集的大小,请尝试使用.to_a.length #count

Enumerable并不是真正的类,它是一个模块 – 由多个类使用的交叉function的集合。

例如, ArraySetHashinclude它 – 您可以调用它们上的任何Enumerable方法。

Enumerable值得注意的是它只需要很少的“主机”类。 您需要做的就是定义each方法并include Enumerable ,并且您可以免费获得所有这些方法! 例:

 class CountUntil def initialize(number) @number = number end include Enumerable def each current = 0 while current < @number yield current current += 1 end end end # Usage: CountUntil.new(10).map { |n| n * 5 } # => [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] 

正如你所看到的,我从未定义过CountUntil#map ,但是我从包含Enumerable免费获得了它。

要解决有关length的问题:并非所有包含Enumerable类都定义了长度,即使大多数类都有。 例如, Enumerator可用于创建无限流。