Como el mensaje de error ya le dice, el problema es que tiene un TypeError
. El hecho de que Ruby se escriba de manera dinámica e implícita no significa que no tenga que pensar en los tipos.
El tipo de Enumerable#inject
sin un acumulador explícita (esto generalmente se llama reduce
) es algo así como
reduce :: [a] → (a → a → a) → a
o en una notación más Rubyish acabo de componer
Enumerable[A]#inject {|A, A| A } → A
Usted notará que todos los tipos son iguales El tipo de elemento del Enumerable
, los dos tipos de argumento del bloque, el tipo de retorno del bloque y el tipo de retorno del método general.
En su caso, los tipos para el bloque simplemente no suman. El bloque pasa dos String
sy se supone que devuelve un String
. Pero llama al método +
en el primer argumento (que es un String
) con un argumento que es Integer
. Pero String#+
no toma Integer
solo toma String
o más precisamente algo que puede ser convertido a String
, es decir, algo que responde a #to_str
. Es por eso que obtienes un TypeError
por String#+
.
El tipo de Enumerable#inject
con un acumulador explícita (esto generalmente se llama fold
) es algo así como
fold :: [b] → a → (a → b → a) → a
o
Aquí vemos que el acumulador puede tener un diferente tipo que el tipo de elemento de la colección. Que es precisamente lo que necesitas.
Estas dos reglas generalmente obtienen a través de todos los problemas relacionados con la PI Enumerable#inject
:
- del tipo de acumulador y el tipo de retorno del bloque debe ser el mismo
- cuando no está pasando un acumulador explícita, la tipo de acumulador es el mismo que el tipo de elemento
Regla # 1 será lo más a menudo que morder cuando haces algo como
acc[key] = value
en su bloque, porque las asignaciones evalúan el valor asignado, no el receptor de la asignación. Tendrá que reemplazar esto con
acc.tap { acc[key] = value }
En su caso particular, las dos soluciones ya se han mencionado. O bien utilizar un acumulador explícita
ary.reduce(0){|acc, e| acc + e.length }
o convertir a enteros primeros
ary.map(&:length).reduce(:+)
puedo encontrar la siguiente sintaxis muy agradable '[ 'hola', 'pila', 'desbordamiento']. Mapa (y : length) .inject (&: +) 'pero ciertamente no es relevante para su pregunta. –
@Jonas, sí, eso es genial. Y como la reducción es una sumatoria, podemos escribir: ['hola', 'pila', 'desbordamiento'], mapa (&: longitud) .sum – tokland
Sí, si está utilizando http://api.rubyonrails.org/classes /Enumerable.html puedes Hasta donde yo sé, no hay 'sum' en Ruby estándar. –