2010-03-22 12 views
9

Estoy creando una aplicación de rieles y han utilizado este código en uno de mis métodos¿Por qué necesito usar .inject (0) en lugar de .inject para que esto funcione?

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

item_numbers es una matriz de objetos de mi mesa item_numbers. El método .amount que les aplico busca el valor de un item_number en una tabla separada y lo devuelve como un objeto BigDecimal. Obviamente, el método de inyección luego agrega todos los objetos i.amount devueltos y esto funciona bien.

Tengo curiosidad de por qué no funcionó cuando escribí esta declaración como

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

Según mi libro piqueta de confianza éstos deben ser equivalentes. ¿Es porque i.amount es un BigDecimal? Si es así, ¿por qué ahora funciona? Si no, entonces ¿por qué no funciona?

Respuesta

14

lo que podemos leer en la API:.

Si no explícitamente especificar una valor inicial para la nota, luego utiliza el primer elemento de la colección que se usa como el valor inicial de la nota.

Así que item_numbers [0] se especificará como un valor inicial, pero no es un número, es un objeto. Así que tenemos un error

método indefinido `+ '.

así que tenemos que especificar como valor inicial 0

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

+0

Usted puede hacer una pequeña prueba (10..15) .inject hacer | suma, i | p suma suma + i final volverá: 10, 21, 33, 46, 60 => 75 como se puede ver _sum_ obtiene primer elemento de matriz como valor inicial – fl00r

+0

lo explica muy bien. Gracias. – brad

7

Es porque está accediendo a i.amount en lugar de simplemente i. En la versión que no funciona, está implícitamente haciendo item_numbers[0] + item_numbers[1].amount + ....

Una taquigrafía sería item_numbers.map(&:amount).inject(&:+), pero de esa manera puede dar como resultado dos iteraciones sobre la lista, si map no devuelve un enumerador.

Si eso no te convence, mira lo que se imprime si definimos un método amount en Fixnum que imprime el valor antes de devolverlo:

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> 

podemos ver claramente que no se llama amount en el primer elemento cuando un valor de partida no se pasa explícitamente en

+0

1 para exemple claro que ilustra el comportamiento perfectamente – Jean

Cuestiones relacionadas