为什么我们可以说`arr.inject(:+)`但是必须说`arr.map(&:to_s)`?

时间:2015-12-30 19:51:02

标签: ruby

似乎我们总是可以使用&:+。为什么inject:+必须map时需要&:to_s?如果原因是map不能采用符号但必须采取阻止,那么map是否也采用符号会有意义吗?

[1,3,5].inject(:+)   # => 9
[1,3,5].inject(&:+)  # => 9
[1,3,5].map(&:to_s)  # => ["1", "3", "5"]
[1,3,5].map(:to_s)   # => ArgumentError: wrong number of arguments (1 for 0)

2 个答案:

答案 0 :(得分:4)

这是设计的。 inject允许使用替代语法来获取符号,而map始终需要一个块。

inject中允许使用符号参数但map中不允许的原因是因为inject总是返回生成的迭代对象,而map旨在返回块不存在时的Enumerator实例。如果块不存在,如果必须查看是否提供了符号参数以决定是返回Enumerator还是映射的Array实例,则会变得复杂。因此,Ruby设计者为map等方法制定了一个简单的规则,即缺少一个块意味着返回值为Enumerator

具有讽刺意味的是,inject允许符号的一个缺点是,符号不能作为inject中的初始值传递。但很可能,Ruby的设计者决定使用这种情况很少见。

答案 1 :(得分:4)

这是设计的。具体来说,inject / reduce不需要完整的符号到proc语法(&:+),而是只允许传递符号(:+)(不同的行为)。

请注意,在这种特定情况下,传递符号与传递从符号派生的proc不同。

From the Ruby documentation

  

通过应用由 a block a symbol 指定的二进制操作来组合枚举的所有元素,该操作命名方法或运算符。

     

如果指定一个块,那么对于枚举中的每个元素,该块将传递一个累加器值(memo)和该元素。如果您指定了符号,则集合中的每个元素都将传递给命名的备忘录方法。在任何一种情况下,结果都将成为备忘录的新值。在迭代结束时,memo的最终值是方法的返回值。