method for ruby syntax operators parameter-passing

for - ruby method



¿Qué significa mapa(&: nombre) en Ruby? (14)

Encontré este código en un RailsCast :

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

¿Qué significa el (&:name) en el map(&:name) ?


(&: name) es la abreviatura de (&: name.to_proc) es igual que tags.map{ |t| t.name }.join('' '') tags.map{ |t| t.name }.join('' '')

to_proc está implementado en C


Aquí :name es el símbolo que apunta al name del método del objeto de etiqueta. Cuando pasamos &:name to map , tratará el name como un objeto proc. Para abreviar, tags.map(&:name) actúa como:

tags.map do |tag| tag.name end


Aunque ya tenemos excelentes respuestas, mirando la perspectiva de un principiante, me gustaría agregar la información adicional:

¿Qué significa mapa (&: nombre) en Ruby?

Esto significa que está pasando otro método como parámetro a la función de mapa. (En realidad, está pasando un símbolo que se convierte en un proceso. Pero esto no es tan importante en este caso en particular).

Lo importante es que tiene un method llamado name que será utilizado por el método de mapa como un argumento en lugar del estilo de block tradicional.


Dos cosas están sucediendo aquí, y es importante entender ambas.

Como se describe en otras respuestas, se Symbol#to_proc método Symbol#to_proc .

Pero la razón to_proc se llama a to_proc en el símbolo es porque se pasa a map como un argumento de bloque. Colocar & delante de un argumento en una llamada de método hace que se pase de esta manera. Esto es cierto para cualquier método de Ruby, no solo para map con símbolos.

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)

El Symbol se convierte en un Proc porque se pasa como un bloque. Podemos mostrar esto intentando pasar un proc a .map sin el signo:

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"]

Aunque no es necesario convertirlo, el método no sabrá cómo usarlo porque espera un argumento de bloqueo. Pasándolo con & da .map el bloque que espera.


Es equivalente a

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


Es lo mismo que a continuación:

def tag_names if @tag_names @tag_names else tags.map{ |t| t.name }.join('' '') end


Es taquigrafía para tags.map { |tag| tag.name }.join('' '') tags.map { |tag| tag.name }.join('' '')


Es una abreviatura de tags.map(&:name.to_proc).join('' '')

Si foo es un objeto con un método to_proc , entonces puede pasarlo a un método como &foo , que llamará foo.to_proc y usarlo como el bloque del método.

El método Symbol#to_proc fue originalmente agregado por ActiveSupport pero se integró en Ruby 1.8.7. Esta es su implementación:

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


La respuesta de Josh Lee es casi correcta, excepto que el código Ruby equivalente debería ser el siguiente.

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

no

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

Con este código, cuando se ejecuta la print [[1,''a''],[2,''b''],[3,''c'']].map(&:first) , Ruby divide la primera entrada [1,''a''] en 1 y'' a ''para dar obj 1 y args* '' a ''para causar un error ya que el objeto Fixnum 1 no tiene el método self (que es: primero).

Cuando se ejecuta [[1,''a''],[2,''b''],[3,''c'']].map(&:first) ;

  1. :first es un objeto Símbolo, por lo tanto, cuando &:first se asigna a un método de mapa como parámetro, se invoca el Símbolo # to_proc.

  2. el mapa envía el mensaje de llamada a: first.to_proc con el parámetro [1,''a''] , por ejemplo, se :first.to_proc.call([1,''a'']) .

  3. El procedimiento to_proc en la clase de símbolos envía un mensaje de envío a un objeto de matriz ( [1,''a''] ) con el parámetro (: primero), por ejemplo, [1,''a''].send(:first) Se ejecuta [1,''a''].send(:first) .

  4. itera sobre el resto de los elementos en [[1,''a''],[2,''b''],[3,''c'']] objeto.

Esto es lo mismo que ejecutar la expresión [[1,''a''],[2,''b''],[3,''c'']].map(|e| e.first) .


Otra taquigrafía fresca, desconocida para muchos, es

array.each(&method(:foo))

que es una taquigrafía para

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

Al llamar a method(:foo) , tomamos un objeto Method de self que representa su método foo , y usamos el & para indicar que tiene un method to_proc que lo convierte en un Proc .

Esto es muy útil cuando quieres hacer cosas sin puntos . Un ejemplo es verificar si hay alguna cadena en una matriz que sea igual a la cadena "foo" . Existe la forma convencional:

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

Y ahí está el camino libre de puntos:

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

La forma preferida debería ser la más legible.


Si bien también #to_proc que el símbolo #to_proc magic puede funcionar con cualquier clase, no solo con Symbol. Muchos Rubyists eligen definir #to_proc en la clase Array:

class Array def to_proc proc { |receiver| receiver.send *self } end end # And then... [ ''Hello'', ''Goodbye'' ].map &[ :+, '' world!'' ] #=> ["Hello world!", "Goodbye world!"]

Ampersand & works envía to_proc mensaje to_proc en su operando, que, en el código anterior, pertenece a la clase Array. Y como #to_proc método #to_proc en Array, la línea se convierte en:

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


significa

array.each(&:to_sym.to_proc)


map (&: name) toma un objeto enumerable (etiquetas en su caso) y ejecuta el método de nombre para cada elemento / etiqueta, generando cada valor devuelto del método.

Es una taquigrafía para

array.map { |element| element.name }

que devuelve la matriz de nombres de elementos (etiquetas)


tags.map(&:name)

es lo mismo que

tags.map{|tag| tag.name}

&:name solo usa el símbolo como el nombre del método que se va a llamar.