为什么chunk_while返回Enumerator对象

为什么chunk_while返回一个Enumerator实例?

这段代码:

 array = [0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16] p array.chunk_while {|i,j| i + 1 == j } 

输出这个:

 #:each> 

我有ruby版ruby 2.3.1p112 (2016-04-26 revision 54768) [x64-mingw32]

Enumerable模块中的方法(如chunk_while )要求接收者是枚举器,即Enumerator类的实例。 因此,如果一个Enumerable方法(如chunk_while返回一个枚举器,它可以是另一个Enumerable方法的接收者(该方法可以是另一个Enumerable方法的接收者,依此类推)。 这称为方法链 。 这就是为什么你看到许多Enumerable方法返回一个枚举器,如果没有提供块。

将枚举器作为接收器的方法的链接还可以包括其他模块或类Enumerator ,例如Enumerator #with_index 。

这就是我们可以编写如下表达式的原因。

 array.chunk_while {|i,j| i + 1 == j }.map.with_index { |a,i| i.even? ? a.reduce(:+) : 0 } #=> [15, 0, 31] 

让我们打破这个。

 e0 = array.chunk_while {|i,j| i + 1 == j } #=> #:each> e1 = e0.map #=> #:each>:map> e2 = e1.with_index #=> #:each>:map>:with_index> e2.each { |a,i| i.even? ? a.reduce(:+) : 0 } #=> [15, 0, 31] 

检查生成e0e1e2的操作的返回值。 e1e2可以被认为是复合枚举器

实际上, chunk_while几乎总是链接到另一个方法,因此它返回一个枚举器是有意义的。

您可能会问,“为什么所有可枚举的方法都需要一个作为枚举器的接收器,考虑到chunk_while接收器, array ,不是枚举器”? 答案在于,包含Enumerable模块的每个类都必须有一个返回枚举器的方法。 因此可以写一个

 array.each.chunk_while {|i,j| i + 1 == j }.to_a 

但Ruby可以省去你的麻烦。 当Ruby看到在数组上调用的方法需要枚举器作为其接收器时,它将为您调用每个Array# 。 所有具有方法的类都是如此。