Why would #each_with_object and #inject switch the order of block parameters?

有些话、适合烂在心里 提交于 2019-12-23 10:39:32

问题


#each_with_object and #inject can both be used to build a hash.

For example:

matrix = [['foo', 'bar'], ['cat', 'dog']]

some_hash = matrix.inject({}) do |memo, arr|
  memo[arr[0]] = arr
  memo # no implicit conversion of String into Integer (TypeError) if commented out
end
p some_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]}

another_hash = matrix.each_with_object({}) do |arr, memo|
  memo[arr[0]] = arr
end
p another_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]}

One of the key differences between the two is #each_with_object keeps track of memo through the entire iteration while #inject sets memo equal to the value returned by the block on each iteration.

Another difference is the order or the block parameters.

Is there some intention being communicated here? It doesn't make sense to reverse the block parameters of two similar methods.


回答1:


They have a different ancestry.

  • each_with_object has been added to Ruby 1.9 in 2007
  • inject goes back to Smalltalk in 1980

I guess if the language were designed with both methods from the begin they would likely expect arguments in the same order. But this is not how it happened. inject has been around since the begin of Ruby whereas each_with_object has been added 10 years later only.

inject expects arguments in the same order as Smalltalk's inject:into:

collection inject: 0 into: [ :memo :each | memo + each ]

which does a left fold. You can think of the collection as a long strip of paper that is folded up from the left and the sliding window of the fold function is always the part that has already been folded plus the next element of the remaining paper strip

# (memo = 0 and 1), 2, 3, 4  
# (memo = 1 and 2), 3, 4                 
# (memo = 3 and 3), 4                    
# (memo = 6 and 4)                      

Following the Smalltalk convention made sense back then since all the initial methods in Enumerable are taken from Smalltalk and Matz did not want to confuse people who are familiar with Smalltalk.

Nor could anyone have the foresight to know that would happen in 2007 when each_with_object was introduced to Ruby 1.9 and the order of argument reflects the lexical order of the method name, which is each ... object.

And hence these two methods expect arguments in different orders for historical reasons.



来源:https://stackoverflow.com/questions/41783001/why-would-each-with-object-and-inject-switch-the-order-of-block-parameters

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!