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

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

#each_with_object and #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 设置为等于每次迭代都会阻塞。

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

这里有什么意图传达吗?将两个相似方法的block参数取反没有意义

他们有不同的血统。

  • each_with_object 已于 2007 年添加到 Ruby 1.9
  • inject 回到 1980 年的 Smalltalk

我想如果从一开始就使用这两种方法设计语言,他们可能会期望参数的顺序相同。但事实并非如此。 inject 自 Ruby 开始就存在,而 each_with_object 仅在 10 年后添加。

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

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

左折。你可以把集合想象成一条长长的纸条,从左边向上折叠起来,折叠函数的滑动window永远是已经折叠的部分加上剩余纸条的下一个元素

# (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

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