为什么我需要使用 .inject(0) 而不是 .inject 来完成这项工作?

发布于 2024-08-26 06:06:29 字数 454 浏览 6 评论 0原文

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

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

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

我只是好奇为什么当我写下这个声明时它不起作用根据

item_numbers.inject {|sum, i| sum + i.amount}

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

I am creating a rails app and have used this code in one of my methods

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

item_numbers is an array of objects from my item_numbers table. The .amount method that I apply to them looks up the value of an item_number in a separate table and returns it as a BigDecimal object. Obviously the inject method then adds all of the returned i.amount objects and this works just fine.

I am just curious as to why it didn't work when I wrote this statement as

item_numbers.inject {|sum, i| sum + i.amount}

According to my trusty pickaxe book these should be equivalent. Is it because i.amount is a BigDecimal? If so, why does it now work? If not, then why doesn't it work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

若水般的淡然安静女子 2024-09-02 06:06:29

我们可以从 API 中读取到:

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

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

未定义的方法“+”。

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

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

What we can read in API:

If you do not explicitly specify an
initial value for memo, then uses the
first element of collection is used as
the initial value of memo.

So item_numbers[0] will be specified as an initial value - but it is not a number, it is an object. So we have got an error

undefined method `+'.

So we have to specify initial value as 0

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

牛↙奶布丁 2024-09-02 06:06:29

这是因为您正在访问 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当未显式传入起始值时,不会在第一个元素上调用。

It's because you are accessing i.amount as opposed to just plain i. In the version that doesn't work, you're implicitly doing item_numbers[0] + item_numbers[1].amount + ....

One shorthand would be item_numbers.map(&:amount).inject(&:+), but that way can result in two iterations over the list, if map doesn't return an enumerator.

If that didn't convince you, look at what gets printed out if we define a method amount on Fixnum that prints the value before returning it:

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>

We can see clearly that amount is not called on the first element when a starting value is not explicitly passed in.

笨死的猪 2024-09-02 06:06:29

有一天我也用头撞它,所以我试着想象它。希望它有帮助。在此处输入图像描述

I was also banging my head against it some day, so I tried to visualize it. Hope it helps.enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文