为什么我需要使用.inject(0)而不是.inject才能使这个工作?

bra*_*rad 11 ruby ruby-on-rails inject

我正在创建一个rails应用程序,并在我的一个方法中使用了此代码

item_numbers.inject(0) {|sum, i| sum + i.amount}
Run Code Online (Sandbox Code Playgroud)

item_numbers是我的item_numbers表中的一个对象数组.我应用于它们的.amount方法在一个单独的表中查找item_number的值,并将其作为BigDecimal对象返回.显然,inject方法然后添加所有返回的i.amount对象,这很好用.

我只是好奇为什么当我把这句话写成时它不起作用

item_numbers.inject {|sum, i| sum + i.amount}
Run Code Online (Sandbox Code Playgroud)

根据我可信赖的镐书,这些应该是等价的.是因为i.amount是BigDecimal吗?如果是这样,为什么它现在有用?如果没有,那么为什么它不起作用.

fl0*_*00r 17

我们在API中可以阅读的内容:

如果没有为memo显式指定初始值,则使用collection的第一个元素作为memo的初始值.

因此item_numbers [0]将被指定为初始值 - 但它不是数字,而是一个对象.所以我们遇到了错误

未定义的方法`+'.

所以我们必须将初始值指定为0

item_numbers.inject(0){| sum,i | 总和+ i}


Mar*_*off 7

这是因为你正在访问i.amount而不是简单的访问i.在不起作用的版本中,你是隐含的item_numbers[0] + item_numbers[1].amount + ....

一种简写是item_numbers.map(&:amount).inject(&:+),但是如果map不返回枚举器,那么这种方式可能导致列表上的两次迭代.

如果这没有说服你,如果我们amount在Fixnum上定义一个方法,在返回之前打印该值,请查看打印出来的内容:

irb(main):002:1>   def amount
irb(main):003:2>     puts "My amount is: #{self}"
irb(main):004:2>     return self
irb(main):005:2>   end
irb(main):006:1> end
=> nil
irb(main):007:0> [1,2,3].inject { |sum, i| sum + i.amount }
My amount is: 2
My amount is: 3
=> 6
irb(main):008:0> [1,2,3].inject(0) { |sum, i| sum + i.amount }
My amount is: 1
My amount is: 2
My amount is: 3
=> 6
irb(main):009:0>
Run Code Online (Sandbox Code Playgroud)

我们可以清楚地看到,amount当未明确传入起始值时,第一个元素上没有调用.