539 votes

Que signifie map(&:name) en Ruby ?

J'ai trouvé ce code dans un RailsCast :

def tag_names
  @tag_names || tags.map(&:name).join(' ')
end

Que fait le (&:name) en map(&:name) C'est-à-dire ?

133 votes

J'ai entendu dire que cela s'appelait "colon bretzel", d'ailleurs.

6 votes

Haha. Je connais ça comme une esperluette. Je n'ai jamais entendu dire que c'était un "bretzel", mais c'est logique.

1 votes

Vous pouvez également supprimer les crochets tags.map &:name pour l'entrée la plus courte.

538voto

Josh Lee Points 53741

C'est un raccourci pour tags.map(&:name.to_proc).join(' ')

Si foo est un objet avec un to_proc vous pouvez alors le passer à une méthode en tant que &foo qui appellera foo.to_proc et l'utiliser comme bloc de la méthode.

Le site Symbol#to_proc a été ajoutée à l'origine par ActiveSupport mais a été intégrée dans Ruby 1.8.7. Voici son implémentation :

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end

44 votes

C'est une meilleure réponse que la mienne.

98 votes

Tags.map(:name.to_proc) est lui-même un raccourci pour tags.map { |tag| tag.name }

5 votes

Ce n'est pas du code ruby valide, vous avez toujours besoin de l'option & c'est-à-dire tags.map(&:name.to_proc).join(' ')

192voto

Gerry Points 2919

Un autre raccourci cool, inconnu de beaucoup, est

array.each(&method(:foo))

qui est un raccourci pour

array.each { |element| foo(element) }

En appelant method(:foo) nous avons pris un Method l'objet de self qui représente son foo et a utilisé la méthode & pour signifier qu'il a un to_proc méthode qui le convertit en un Proc .

C'est très utile lorsque vous voulez faire des choses sans point le style. Un exemple est de vérifier s'il y a une chaîne dans un tableau qui est égale à la chaîne "foo" . Il y a la voie conventionnelle :

["bar", "baz", "foo"].any? { |str| str == "foo" }

Et il y a la voie sans points :

["bar", "baz", "foo"].any?(&"foo".method(:==))

La méthode privilégiée doit être la plus lisible.

30 votes

array.each{|e| foo(e)} est encore plus court :-) +1 en tout cas

0 votes

Pourriez-vous mapper un constructeur d'une autre classe en utilisant &method ?

4 votes

@finishingmove ouais je suppose. Essayez ceci [1,2,3].map(&Array.method(:new))

82voto

Ben Alpert Points 30381

C'est l'équivalent de

def tag_names
  @tag_names || tags.map { |tag| tag.name }.join(' ')
end

50voto

Boris Stitnicky Points 5409

Notons également que l'esperluette #to_proc La magie peut fonctionner avec n'importe quelle classe, pas seulement avec la Symbole. De nombreux Rubyistes choisissent de définir #to_proc sur la classe Array :

class Array
  def to_proc
    proc { |receiver| receiver.send *self }
  end
end

# And then...

[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]

Ampersand & fonctionne en envoyant to_proc sur son opérande, qui, dans le code ci-dessus, est de la classe Array. Et comme j'ai défini #to_proc sur Array, la ligne devient :

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }

0 votes

C'est de l'or pur !

41voto

Oliver N. Points 1904

C'est un raccourci pour tags.map { |tag| tag.name }.join(' ')

0 votes

Non, c'est dans Ruby 1.8.7 et plus.

0 votes

Est-ce un simple idiome pour map ou Ruby interprète-t-il toujours le "&" d'une manière particulière ?

7 votes

@collimarco : Comme le dit jleedev dans sa réponse, l'unaire & appels des opérateurs to_proc sur son opérande. Elle n'est donc pas spécifique à la méthode map, et fonctionne en fait sur toute méthode qui prend un bloc et lui transmet un ou plusieurs arguments.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X