How does "(1..4).inject(&:+)" work in Ruby

ghz 1years ago ⋅ 2216 views

Question

I find this code in Ruby to be pretty intriguing

(1..4).inject(&:+)

Ok, I know what inject does, and I know this code is basically equivalent to

(1..4).inject(0) {|a,n| a + n}

but how exactly does it work?

Why &:+ is the same as writing the block {|a,n| a + n}?

Why it doesn't need an initial value? I'm ok with the inicial value being 0, but (1..4).inject(&:*) also works, and there the initial value must be 1...


Answer

From [Ruby documentation](http://ruby- doc.org/ruby-1.9/classes/Enumerable.html#M002714):

If you specify a symbol instead, then each element in the collection will be passed to the named method of memo

So, specifying a symbol is equivalent to passing the following block: {|memo, a| memo.send(sym, a)}

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, there is no magic, Ruby simply takes the first element as the initial value and starts injecting from the second element. You can check it by writing [].inject(:+): it returns nil as opposed to [].inject(0, :+) which returns 0.

Edit: I didn't notice the ampersand. You don't need it, inject will work with a symbol. But if you do write it, the symbol is converted to block, it can be useful with [other methods](https://stackoverflow.com/questions/1217088/what-does-mapname-mean- in-ruby)