中的方法可枚举 http://ruby-doc.org/core-2.3.0/Enumerable.html模块,例如chunk_while
,要求接收者是枚举器,即类的实例枚举器 http://ruby-doc.org/core-2.3.0/Enumerator.html。因此,如果一个Enumerable
方法如chunk_while
返回一个枚举器,它可以是另一个枚举器的接收者Enumerable
方法(并且该方法可以是另一个方法的接收者Enumerable
方法等)。这就是所谓的方法链接。这就是为什么你会看到很多Enumerable
如果未提供块,方法将返回一个枚举器。
以枚举器作为接收者的方法的链接还可能包括其他模块或类中的方法Enumerator
, 例如枚举器#with_index http://ruby-doc.org/core-2.3.0/Enumerator.html#method-i-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 }
#=> #<Enumerator: #<Enumerator::Generator:0x007fa01b9639e0>:each>
e1 = e0.map
#=> #<Enumerator: #<Enumerator: #<Enumerator::Generator:0x007fa01b9639e0>:each>:map>
e2 = e1.with_index
#=> #<Enumerator: #<Enumerator: #<Enumerator:
# #<Enumerator::Generator:0x007fa01b9639e0>:each>:map>:with_index>
e2.each { |a,i| i.even? ? a.reduce(:+) : 0 }
#=> [15, 0, 31]
检查产生的操作的返回值e0
, e1
and e2
. e1
and e2
可能被认为是复合枚举器.
作为实践问题,chunk_while
几乎总是链接到另一个方法,因此它返回一个枚举器是有意义的。
您可能会问,“为什么所有可枚举方法都必须需要一个作为枚举器的接收器,考虑到chunk_while
示例中的接收器,array
,不是一个枚举器”?答案在于,每个包含Enumerable
模块必须有一个方法each
返回一个枚举器。因此可以写
array.each.chunk_while {|i,j| i + 1 == j }.to_a
但 Ruby 可以帮你省去麻烦。 Ruby 将调用数组#each https://stackoverflow.com/questions/40066614/convert-array-of-hashes-to-array/40066893?noredirect=1#comment67536024_40066893当它发现在数组上调用的方法需要一个枚举器作为其接收者时,为您提供帮助。所有具有方法的类都是如此each
.