Vous êtes probablement familier avec le raccourci Ruby suivant ( a
est un tableau):
a.map(&:method)
Par exemple, essayez ce qui suit dans irb:
>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]
La syntaxe a.map(&:class)
est un raccourci pour a.map {|x| x.class}
.
En savoir plus sur cette syntaxe dans " Que signifie map (&: name) dans Ruby? ".
Grâce à la syntaxe &:class
, vous effectuez un appel de méthode class
pour chaque élément du tableau.
Ma question est: pouvez-vous fournir des arguments à l'appel de méthode? Et si oui, comment?
Par exemple, comment convertir la syntaxe suivante
a = [1,3,5,7,9]
a.map {|x| x + 2}
à la &:
syntaxe?
Je ne suggère pas que la &:
syntaxe est meilleure. Je suis simplement intéressé par les mécanismes d'utilisation de la &:
syntaxe avec des arguments.
Je suppose que vous savez que +
c'est une méthode sur la classe Integer. Vous pouvez essayer ce qui suit dans irb:
>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2
Symbol#with
qu'il n'existe pas dans la bibliothèque principale et que la définition de cette méthode soit moins destructrice que la redéfinition d'une méthode existante, elle est toujours en train de changer (c'est-à-dire d'écraser) l'implémentation de la classe principale de la bibliothèque ruby. La pratique doit être effectuée avec parcimonie et avec une grande prudence. \ n \ n Veuillez envisager d'hériter de la classe existante et de modifier la classe nouvellement créée. Cela permet généralement d'obtenir des résultats comparables sans les effets secondaires négatifs du changement des classes de rubis de base.Symbol
classe - ce n'est pas trivial (si possible), car c'est une telle classe de base (elle n'a pas denew
méthode, par exemple), et son utilisation sera lourde (si même possible), ce qui vaincra le but de l'amélioration ... si vous pouvez montrer une implémentation qui utilise cela et obtient des résultats comparables - partagez-la!with
méthode, définissezcall
. Ensuite, vous pouvez faire des choses commea.map(&:+.(2))
depuisobject.()
utilise la#call
méthode. Et pendant que vous y êtes, vous pouvez écrire des choses amusantes comme:+.(2).(3) #=> 5
- vous sentez en quelque sorte LISPy, non?Pour votre exemple peut être fait
a.map(&2.method(:+))
.Voici comment cela fonctionne: -
2.method(:+)
donne unMethod
objet. Ensuite&
, en2.method(:+)
fait, une#to_proc
méthode d' appel , qui en fait unProc
objet. Puis suivez Comment appelez-vous l'opérateur &: dans Ruby? .la source
Pry
sorties ci-dessus, vous pouvez l'obtenir, comment ça marche.+
est commutatif.Comme le message auquel vous avez lié le confirme, ce
a.map(&:class)
n'est pas un raccourci poura.map {|x| x.class}
mais poura.map(&:class.to_proc)
.Cela signifie qu'il
to_proc
est appelé sur tout ce qui suit l'&
opérateur.Vous pouvez donc lui donner directement un à la
Proc
place:Je sais que très probablement cela va à l'encontre du but de votre question, mais je ne vois pas d'autre solution - ce n'est pas que vous spécifiez la méthode à appeler, vous lui passez simplement quelque chose qui répond
to_proc
.la source
my_proc = Proc.new{|i| i + 1}
,[1,2,3,4].map(&my_proc) => [2,3,4,5]
Réponse courte: Non.
Suite à la réponse de @ rkon, vous pouvez également faire ceci:
la source
&->(_){_ + 2}
soit plus court que{|x| x + 2}
.Au lieu de patcher vous-même les classes principales, comme dans la réponse acceptée, il est plus court et plus propre d'utiliser la fonctionnalité du gem Facets :
la source
Il existe une autre option native pour les énumérables qui n'est jolie que pour deux arguments à mon avis. la classe
Enumerable
a la méthodewith_object
qui en retourne une autreEnumerable
.Vous pouvez donc appeler l'
&
opérateur d'une méthode avec chaque élément et l'objet comme arguments.Exemple:
Dans le cas où vous voudriez plus d'arguments, vous devriez répéter le processus mais c'est moche à mon avis:
la source
Je ne suis pas sûr du
Symbol#with
déjà posté, je l'ai un peu simplifié et ça marche bien:(utilise également
public_send
au lieu desend
pour empêcher d'appeler des méthodes privées,caller
est également déjà utilisé par ruby, donc c'était déroutant)la source