Alessandro Dias

O Parâmetro & (Ampersand)

| Comments

Para que serve o & antes de um parâmetro em Ruby?

O & antes de algum parâmetro é utilizado basicamente de duas formas:

1 Na definição de um método:

1
2
3
def awesome_method &block
  yield if block_given?
end

2 Antes da chamada de um método:

1
  awesome_method &parameter

A primeira forma serve para deixar explícito que o seu método recebe um bloco.
Já a segunda forma funciona assim:
pega o parâmetro, chama o método to_proc e o passa como bloco, idependente de o método ter deixado o bloco explícito ou não. Então basta que o objeto passado responda a to_proc. Você ja deve ter visto parecido com isso:

1
  @users.map &:name

E uma coisa que sempre quis saber é “como um símbolo passado como parâmetro irá no exemplo acima irá retornar o nome de todos usuários?”.
Pesquisei um pouco, e achei como isso é feito Símbolos implementam o to_proc, tá e dai, como funciona esse to_proc`?

1
2
3
4
5
6
7
8
  class Symbol
    # ...
    def to_proc
      Proc.new do |obj, *args|
        obj.send self, *args
      end
    end
    # ...

Ainda um pouco confuso? Vamos destrinchar esse código então. vamos chamar o to_proc para o símbolo :name

1
2
3
4
5
  #...
  Proc.new do |obj, *args|
    obj.send :name, *args
  end
  #...

o map passa como parâmetro para o bloco um item da coleção, nesse caso um user, vamos adicioná-lo no código, e já que apenas um argumento é passado podemos remover o *args para simplificar.

1
2
3
4
5
  #...
  Proc.new do |user|
    user.send :name # => equivalente a user.name
  end
  #...

Mais simples agora? O método send envia para o user a mensagem :name, porque na verdade em Ruby metódos não são chamados, são mensagens enviadas ao objeto. o resultado final seria algo equivalente a isso:

1
2
3
  @users.map do |user|
    user.send :name # ou user.name
  end

Caso queira saber mais sobre o ampersand: Ruby ampersand parameter demystified

Comments