Probablemente esté familiarizado con la siguiente abreviatura de Ruby ( a
es una matriz):
a.map(&:method)
Por ejemplo, intente lo siguiente en irb:
>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]
La sintaxis a.map(&:class)
es una abreviatura de a.map {|x| x.class}
.
Lea más sobre esta sintaxis en " ¿Qué significa mapa (&: nombre) en Ruby? ".
A través de la sintaxis &:class
, está realizando una llamada class
a un método para cada elemento de la matriz.
Mi pregunta es: ¿puede proporcionar argumentos a la llamada al método? Y si es así, ¿cómo?
Por ejemplo, ¿cómo se convierte la siguiente sintaxis
a = [1,3,5,7,9]
a.map {|x| x + 2}
a la &:
sintaxis?
No estoy sugiriendo que la &:
sintaxis sea mejor. Simplemente estoy interesado en la mecánica de usar la &:
sintaxis con argumentos.
Supongo que sabe que +
es un método en la clase Integer. Puede probar lo siguiente en irb:
>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2
Symbol#with
puede no existir en la biblioteca principal y definir ese método es menos destructivo que redefinir un método existente, todavía está cambiando (es decir, sobrescribiendo) la implementación de la clase principal de la biblioteca ruby. La práctica debe realizarse con mucha moderación y mucha precaución. \ n \ n Considere heredar de la clase existente y modificar la clase recién creada. Esto generalmente logra resultados comparables sin los efectos secundarios negativos de cambiar las clases de rubí centrales.Symbol
clase, no es trivial (si es posible), ya que es una clase central (no tiene ningúnnew
método, por ejemplo), y su uso será engorroso (si es posible), lo que anulará la propósito de la mejora ... si puede mostrar una implementación que lo usa y logra resultados comparables, ¡comparta!with
método, definacall
. Entonces puedes hacer cosas comoa.map(&:+.(2))
ya queobject.()
usa el#call
método. Y mientras lo hace, puede escribir cosas divertidas como:+.(2).(3) #=> 5
: se siente como LISPy, ¿no?Por tu ejemplo se puede hacer
a.map(&2.method(:+))
.Así es como funciona :-
2.method(:+)
da unMethod
objeto. Luego&
, en2.method(:+)
realidad, es un#to_proc
método de llamada , que lo convierte en unProc
objeto. Luego sigue ¿Cómo llamas al operador &: en Ruby? .fuente
Pry
resultados anteriores, puede obtenerlo, ¿cómo está funcionando?+
es conmutativo.Como confirma la publicación a la que vinculó,
a.map(&:class)
no es una abreviatura dea.map {|x| x.class}
sino dea.map(&:class.to_proc)
.Esto significa que
to_proc
se invoca todo lo que sigue al&
operador.Entonces podrías darle directamente un
Proc
en su lugar:Sé que lo más probable es que esto anule el propósito de su pregunta, pero no puedo ver otra forma de evitarlo; no es que usted especifique a qué método llamar, simplemente le pasa algo que responda
to_proc
.fuente
my_proc = Proc.new{|i| i + 1}
,[1,2,3,4].map(&my_proc) => [2,3,4,5]
Respuesta corta: No.
Siguiendo la respuesta de @ rkon, también puedes hacer esto:
fuente
&->(_){_ + 2}
sea más corto que{|x| x + 2}
.En lugar de parchear las clases principales usted mismo, como en la respuesta aceptada, es más corto y más limpio usar la funcionalidad de la gema Facetas :
fuente
Hay otra opción nativa para enumerables que, en mi opinión, es bonita solo para dos argumentos. la clase
Enumerable
tiene el métodowith_object
que luego devuelve otroEnumerable
.Entonces puede llamar al
&
operador para obtener un método con cada elemento y el objeto como argumentos.Ejemplo:
En el caso de que quiera más argumentos debería repetir el proceso pero es feo en mi opinión:
fuente
No estoy seguro de lo que
Symbol#with
ya se publicó, lo simplifiqué un poco y funciona bien:(también se usa en
public_send
lugar desend
para evitar llamar a métodos privados, tambiéncaller
ya lo usa ruby, por lo que esto era confuso)fuente