为什么#each_with_object和#inject会切换块参数的顺序?

#each_with_object和#inject都可用于构建哈希。

例如:

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"]} 

两者之间的主要区别之一是#each_with_object在整个迭代过程中跟踪memo ,而#injectmemo设置为等于每次迭代时块返回的值。

另一个区别是顺序或块参数。

有没有在这里传达意图? 反转两种类似方法的块参数没有意义。

他们有不同的血统。

  • each_with_object已于2007年添加到Ruby 1.9中
  • inject可以追溯到1980年的Smalltalk

我想如果语言是从开头设计的两种方法,他们可能会期望相同顺序的参数。 但事实并非如此。 自从Ruby开始以来, inject已经存在,而each_with_object仅在10年后才被添加。

inject期望参数的顺序与Smalltalk的inject:into:相同inject:into:

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

这是左折。 您可以将该集合视为从左侧折叠起来的长条纸,折叠function的滑动窗口始终是已经折叠的部分以及剩余纸条的下一个元素

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

因为Smalltalk会议在当时有意义,因为Enumerable中的所有初始方法都取自Smalltalk,Matz不想混淆熟悉Smalltalk的人。

任何人都不可能有先见之明知道2007年将each_with_object引入Ruby 1.9并且参数的顺序反映了方法名称的词法顺序,即each ... object

因此,由于历史原因,这两种方法需要不同顺序的参数。