Domanda Cosa significa map (&: name) in Ruby?


Ho trovato questo codice in un RailsCast:

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

Cosa fa il (&:name) in map(&:name) significare?


450
2017-08-01 17:35


origine


risposte:


È una scorciatoia per tags.map(&:name.to_proc).join(' ')

Se foo è un oggetto con a to_proc metodo, quindi puoi passarlo a un metodo come &foo, che chiamerà foo.to_proc e usalo come blocco del metodo.

Il Symbol#to_proc il metodo è stato originariamente aggiunto da ActiveSupport ma è stato integrato in Ruby 1.8.7. Questa è la sua implementazione:

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

471
2017-08-01 17:50



Un'altra fredda stenografia, sconosciuta a molti, è

array.each(&method(:foo))

che è una scorciatoia per

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

A chiamata method(:foo) abbiamo preso un Method oggetto da self quello rappresenta il suo foo metodo e usato il & per significare che ha un to_proc  metodo che lo converte in a Proc.

Questo è molto utile quando vuoi fare le cose libera-punto stile. Un esempio è per verificare se c'è una stringa in una matrice che è uguale alla stringa "foo". C'è il modo convenzionale:

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

E c'è il modo point-free:

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

Il modo preferito dovrebbe essere il più leggibile.


159
2018-03-08 18:07



È equivalente a

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

70
2017-08-01 17:39



Facciamo anche notare che la e commerciale #to_proc la magia può funzionare con qualsiasi classe, non solo con il simbolo. Molti Rubyisti scelgono di definire #to_proc sulla classe Array:

class Array
  def to_proc
    proc { |receiver| receiver.send *self }
  end
end

# And then...

[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]

E commerciale & funziona inviando to_proc messaggio sul suo operando, che, nel codice precedente, è di classe Array. E da quando ho definito #to_proc metodo su Array, la linea diventa:

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

39
2017-11-20 12:38



È una scorciatoia per tags.map { |tag| tag.name }.join(' ')


35
2017-08-01 17:37



tags.map(&:name)

equivale a

tags.map{|tag| tag.name}

&:name usa semplicemente il simbolo come nome del metodo da chiamare.


24
2017-11-01 03:23



La risposta di Josh Lee è quasi corretta, tranne che il codice Ruby equivalente avrebbe dovuto essere il seguente.

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

non

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

Con questo codice, quando print [[1,'a'],[2,'b'],[3,'c']].map(&:first) viene eseguito, Ruby divide il primo input [1,'a'] in 1 e 'a' da dare obj 1 e args* 'a' per causare un errore poiché l'oggetto Fixnum 1 non ha il metodo self (che è: primo).


quando [[1,'a'],[2,'b'],[3,'c']].map(&:first) è eseguito;

  1. :first è un oggetto simbolo, quindi quando &:first viene assegnato a un metodo mappa come parametro, viene richiamato il simbolo # to_proc.

  2. map invia il messaggio di chiamata a: first.to_proc con parametro [1,'a'], per esempio., :first.to_proc.call([1,'a']) viene eseguito.

  3. La procedura to_proc nella classe Symbol invia un messaggio di invio a un oggetto array ([1,'a']) con parametro (: primo), ad es. [1,'a'].send(:first) viene eseguito.

  4. itera sopra il resto degli elementi in [[1,'a'],[2,'b'],[3,'c']] oggetto.

Questo è come l'esecuzione [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first) espressione.


14
2018-01-23 21:08