Que signifie «& méthode (: fonction)»?

15

Que veut &method(:function)dire? Par exemple, j'ai cette ligne:

res = integrate(0, 1, a, &method(:function))
RubyBeginner
la source
Deux excellentes réponses (jusqu'à présent). Quel chanceux êtes-vous!
Cary Swoveland

Réponses:

13

Disons que nous avons une méthode

def add_one(num)
  num + 1
end

et un tableau de chaînes

arr = ["1", "2"]

Nous voulons mapla liste des chaînes à leurs sorties correspondantes de add_one.

Pour commencer, nous pouvons appeler

nums = arr.map(&:to_i)

C'est la même chose que

nums = arr.map do |str|
  str.to_i
end

Vous pouvez voir Que signifie la carte (&: nom) dans Ruby? pour plus d'informations à ce sujet.

Cependant, cela ne fonctionnera pas d'appeler:

nums.map(&:add_one)

Pourquoi? Parce que les nombres n'ont pas de méthode intégrée add_one. Vous obtiendrez donc un NoMethodError.

Ainsi, plutôt que de fournir simplement un nom de méthode, :add_one vous pouvez passer une méthode liée method(:add_one) :

nums.map(&method(:add_one))

Maintenant, plutôt que chaque num étant utilisé comme récepteur pour la add_oneméthode, ils seront utilisés comme arguments . Donc, c'est essentiellement la même chose que:

nums.map do |num|
  add_one(num)
end

Pour donner un autre exemple, comparez les éléments suivants:

[1].map(&:puts)
# this is the same as [1].map { |num| num.puts }
# it raises NoMethodError

[1].map(&method(:puts))
# this is the same as [1].map { |num| puts num }
# it prints 1 successfully
max pleaner
la source
Nitpick: Object#methodretourne une borne Method , pas une UnboundMethod. La méthode est liée à un récepteur parce que vous l'appelez sur une instance et elle sait donc ce qu'est self, alors qu'elle Module#instance_methodretourne une UnboundMethodcar elle ne peut pas savoir avec quelle instance elle va être utilisée.
Jörg W Mittag
@ JörgWMittag Ok merci pour la correction, vous avez raison, je dois l'avoir mélangé .instance_methodparce que je passais juste par la mémoire (défectueuse)
max pleaner
10

method(:function)est un message envoyé (parfois appelé appel de méthode ) au récepteur implicite (ie self). Il envoie le message methodau récepteur implicite (c'est-à-dire self), en le passant :functioncomme seul argument.

:functionest un Symbollittéral, c'est-à-dire qu'il s'agit de la notation littérale de a Symbol. Symbolest un type de données représentant "le nom de quelque chose".

L'opérateur préfixe unaire esperluette &"déroule" un Procdans un bloc . C'est à dire qu'il vous permet de passer un Procoù un bloc est attendu. Si l'objet n'est pas déjà un Proc, il recevra le to_procmessage lui permettant de se convertir en a Proc. (L'opérateur n'est légal que dans une liste d'arguments et uniquement pour le dernier argument. C'est le double du &sigil dans une liste de paramètres, qui "roule" un bloc dans un Procobjet.)

Procest un type de données représentant du code exécutable. C'est la classe de bibliothèque principale de Ruby pour les sous-programmes de première classe.

Donc, ce que cela fait, c'est appeler la methodméthode selfavec :functioncomme argument, appeler to_procla valeur de retour, "dérouler" l' Procobjet résultant dans un bloc et passer ce bloc à l'appel integratecomme si vous aviez écrit quelque chose comme

res = integrate(0, 1, a) do
  # something
end

La methodméthode ici est très probablement, la Object#methodméthode, qui renvoie un objet lié Method .

Donc, dans l'ensemble, cela équivaut quelque peu à

res = integrate(0, 1, a) do |*args, &block|
  function(*args, &block)
end

Mais exprimé dans ce qu'on appelle communément le style sans point .

Jörg W Mittag
la source