【问题标题】:Why do I need to use .inject(0) rather than .inject to make this work?为什么我需要使用 .inject(0) 而不是 .inject 来完成这项工作?
【发布时间】:2011-01-30 07:10:15
【问题描述】:

我正在创建一个 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 吗?如果是这样,为什么它现在有效?如果没有,那为什么它不起作用。

【问题讨论】:

    标签: ruby-on-rails ruby inject


    【解决方案1】:

    这是因为您访问的是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在没有显式传入起始值的情况下不会在第一个元素上调用。

    【讨论】:

    • +1 为清楚的例子,完美地说明了行为
    【解决方案2】:

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

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

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

    未定义的方法`+'。

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

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

    【讨论】:

    • 你可以做一个小测试 (10..15).inject do |sum, i| p sum sum+i end 它将返回: 10, 21, 33, 46, 60 => 75 如您所见 sum 从数组中获取第一项作为初始值
    • 这很好地解释了它。谢谢。
    【解决方案3】:

    有一天我也在用头撞它,所以我试着想象它。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2016-11-02
      • 1970-01-01
      • 2014-11-26
      • 2021-08-17
      • 2022-11-07
      • 2021-12-25
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多