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

时间:2010-03-22 10:54:42

标签: ruby-on-rails ruby inject

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

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

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

我只是好奇为什么当我把这句话写成

时它不起作用
item_numbers.inject {|sum, i| sum + i.amount}

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

3 个答案:

答案 0 :(得分:16)

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

  

如果您没有明确指定   备忘录的初始值,然后使用   集合的第一个元素用作   备忘录的初始值。

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

  

未定义的方法`+'。

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

  

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

答案 1 :(得分:7)

这是因为您正在访问i.amount而不是普通的i。在不起作用的版本中,您隐式执行item_numbers[0] + item_numbers[1].amount + ...

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

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

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>

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

答案 2 :(得分:0)

有一天我也用头撞它,所以我试着想象它。希望它有所帮助。enter image description here