Como muitos já sabem, sou apaixonado pro ruby e já compartilhei vários motivos do por quê. Mas dentre os motivos que dei, não entrei muito em detalhes de códigos no ruby que me deixam sem ar de tão legais e fáceis de implementar. E um exemplo desse tipo de código é o método #inject
que vou explicar pra vocês agora. Espero que se empolguem e que usem ele sabiamente.
Bom, pra quem caiu de paraquedas aqui: o module Enumerable
é o modules que representa uma collection no ruby. Se você tem uma classe que é uma collection, apenas inclua esse module e implemente o método #each
e você terá vários métodos úteis na sua collection.
E um desses métodos é o #inject
, ou #reduce
que é apenas um alias para #inject
. Agora vamos aos detalhes desse método tão maravilhoso.
O conceito em si é muito simples, é apenas uma maneira de combinar todos os elementos da collection em um novo objeto. Ou seja, o método retorna um novo objeto a partir da iteração em todos os elementos.
E para implementar ele fazemos assim:
(1..3).inject(0) do |result, i|
result + i
end
# => 6
Este método acima, soma todos os elementos do range 1..3
. Esse mesmo código pode ser escrito assim: (1..3).inject(0, :+)
. Mas para explicar como o método funciona, vamos ficar com o primeiro exemplo. Como podem ver, só batendo o olho não é muito claro como ele funciona.
Então vou explicar como funciona: o método #inject
itera no Enumerable
e executa o bloco de código para cada iteração, igual ao #each
. Mas o que é esse primeiro parêmtro result
do bloco?
Então, esse é mais complicado de explicar 😁: no primeiro parâmetro do bloco o #inject
passa para você o retorno da execução da iteração anterior, e na primeira iteração, ele é igual ao valor passado por parâmetro para o #inject
, no nosso caso o 0
.
Sacou? No nosso código por exemplo, na primeira iteração o result
é 0
, pois foi o que passamos por parâmetro. Na segunda iteração é 1
, pois somamos o result
que era 0
, com o item da iteração i
, que era 1
, e assim por diante.
O resultado retornado pelo #inject
é o retorno da última iteração.
Meio complicado só pra somar um array né? Mas lembre-se que você pode fazer isso em uma linha de código, e ainda deixar o código bem legível! Olha outra utilidade para essa "belezura":
(1..3).inject(Hash.new) do |result, i|
result[i.to_s] = i
result
end
# => {'1' => 1, ... }
Viu? Facilmente convertemos um range para um hash! Consegue perceber o poder que isso te dá? Então vá e use ele!
Lembre-se, com grandes poderes vêm grandes responsabilidades. Use o inject com conciência, por mais magnífico que ele seja, muitas vezes ele pode ficar bem ilegível, e bem difícil de dar manutenção.
Pra finalizar, uma dica: explore mais os métodos do module Enumerable
, tem outros métodos muito úteis. 😉