Que signifie map ( & : nom) dans Ruby?

j'ai trouvé ce code dans un RailsCast :

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

que signifie (&:name) dans map(&:name) ?

460
demandé sur user22a6db72d7249 2009-08-01 21:35:58
la source

14 ответов

c'est la abréviation de tags.map(&:name.to_proc).join(' ')

si foo est un objet avec une méthode to_proc , alors vous pouvez le passer à une méthode comme &foo , qui appellera foo.to_proc et utiliser que le bloc de la méthode.

la méthode Symbol#to_proc a été ajoutée à l'origine par ActiveSupport mais a été intégrée dans Ruby 1.8.7. C'est sa mise en œuvre:

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end
478
répondu Josh Lee 2012-02-27 20:43:12
la source

une autre sténo cool, inconnue 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 objet de self qui représente sa méthode foo , et utilisé le & pour signifier qu'il a un to_proc méthode qui le convertit en un Proc .

C'est très utile quand vous voulez faire les choses point-libre de style. Un exemple est de vérifier s'il existe une chaîne dans un tableau qui est égal à la chaîne "foo" . Il y a la voie conventionnelle:

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

Et il est le point de façon libre:

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

la méthode préférée devrait être la plus lisible.

161
répondu Gerry 2015-08-09 21:44:35
la source

c'est l'équivalent de

def tag_names
  @tag_names || tags.map { |tag| tag.name }.join(' ')
end
71
répondu Sophie Alpert 2009-08-01 21:39:52
la source

tandis que nous notons également que ampersand #to_proc magie peut fonctionner avec n'importe quelle classe, pas seulement le symbole. Beaucoup de 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!"]

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

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
39
répondu Boris Stitnicky 2016-05-05 22:28:18
la source

c'est la abréviation de tags.map { |tag| tag.name }.join(' ')

35
répondu Oliver N. 2009-08-01 22:06:00
la source
tags.map(&:name)

est Le même que

tags.map{|tag| tag.name}

&:name utilise simplement le symbole comme nom de méthode à appeler.

27
répondu Albert.Qing 2016-11-01 06:23:29
la source

la réponse de Josh Lee est presque correcte sauf que le code Ruby équivalent aurait dû être comme suit.

class Symbol
  def to_proc
    Proc.new do |receiver|
      receiver.send self
    end
  end
end

pas

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

avec ce code, lorsque print [[1,'a'],[2,'b'],[3,'c']].map(&:first) est exécuté, Ruby divise la première entrée [1,'a'] en 1 et 'a' pour donner obj 1 et args* 'a' pour causer une erreur car L'objet Fixnum 1 n'a pas la méthode en soi (qui est :premier).


quand [[1,'a'],[2,'b'],[3,'c']].map(&:first) est exécuté;

  1. :first est un objet Symbol, donc quand &:first est donné à une méthode map comme paramètre, le symbole#to_proc est invoqué.

  2. carte envoie message d'appel à :premier.to_proc avec le paramètre [1,'a'] , par exemple, :first.to_proc.call([1,'a']) est exécuté.

  3. procédure to_proc en classe de symbole envoie un message d'envoi à un objet array ( [1,'a'] ) avec paramètre (:first), par exemple, [1,'a'].send(:first) est exécuté.

  4. itère sur le reste des éléments de [[1,'a'],[2,'b'],[3,'c']] objet.

c'est la même chose que l'expression [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first) .

14
répondu prosseek 2014-01-24 01:14:16
la source

deux choses se produisent ici, et il est important de comprendre les deux.

tel que décrit dans d'autres réponses, la méthode Symbol#to_proc est appelée.

mais la raison pour laquelle to_proc est appelé sur le symbole est parce qu'il est passé à map comme argument de bloc. Placer & devant un argument dans un appel de méthode provoque qu'il soit passé de cette façon. C'est vrai pour N'importe quelle méthode Ruby, pas seulement map avec des symboles.

def some_method(*args, &block)
  puts "args: #{args.inspect}"
  puts "block: #{block.inspect}"
end

some_method(:whatever)
# args: [:whatever]
# block: nil

some_method(&:whatever)
# args: []
# block: #<Proc:0x007fd23d010da8>

some_method(&"whatever")
# TypeError: wrong argument type String (expected Proc)
# (String doesn't respond to #to_proc)

le Symbol est converti en Proc parce qu'il est passé en bloc. Nous pouvons le montrer en essayant de passer un proc à .map sans l'ampersand:

arr = %w(apple banana)
reverse_upcase = proc { |i| i.reverse.upcase }
reverse_upcase.is_a?(Proc)
=> true

arr.map(reverse_upcase)
# ArgumentError: wrong number of arguments (1 for 0)
# (map expects 0 positional arguments and one block argument)

arr.map(&reverse_upcase)
=> ["ELPPA", "ANANAB"]

même si elle n'a pas besoin d'être convertie, la méthode ne saura pas comment l'utiliser car elle attend un argument de bloc. Le passer avec & donne .map le bloc qu'il attend.

8
répondu devpuppy 2016-04-09 04:43:55
la source

(&:nom) est l'abréviation de (&:nom.to_proc) c'est même comme tags.map{ |t| t.name }.join(' ')

to_proc est réellement mis en œuvre en C

5
répondu tessie 2017-10-11 08:55:00
la source

bien que nous ayons déjà de bonnes réponses, en regardant à travers une perspective d'un débutant je voudrais ajouter l'information supplémentaire:

que signifie map(&:name) dans Ruby?

cela signifie que vous passez une autre méthode comme paramètre à la fonction map. (En réalité, vous passez un symbole qui se transforme en proc. Mais ce n'est pas important dans ce cas particulier).

Ce qui est important, c'est que vous ayez un method nommé name qui sera utilisé par la méthode map comme argument au lieu du style traditionnel block .

2
répondu Jonathan Duarte 2017-12-08 18:45:53
la source

ici :name est le symbole qui pointe vers la méthode name de l'objet de la balise. Lorsque nous passerons de &:name à map , nous considérerons name comme un objet proc. En bref, tags.map(&:name) agit comme:

tags.map do |tag|
  tag.name
end
1
répondu timlentse 2016-06-30 09:30:44
la source

signifie

array.each(&:to_sym.to_proc)
1
répondu mminski 2016-12-20 15:25:09
la source

C'est le même que ci-dessous:

def tag_names
  if @tag_names
    @tag_names
  else
    tags.map{ |t| t.name }.join(' ')
end
0
répondu user3078630 2016-06-27 12:32:18
la source

map(&:name) prend un objet énumérable (tags dans votre cas) et exécute la méthode du nom pour chaque élément/étiquette, en sortant chaque valeur retournée de la méthode.

C'est un raccourci pour

array.map { |element| element.name }

qui renvoie le tableau des noms d'éléments(étiquette)

0
répondu Sunda 2018-09-01 07:48:06
la source

Autres questions sur ruby syntax operators parameter-passing