Ich habe diesen Code in einem RailsCast gefunden :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
Was bedeutet das (&:name)in map(&:name)?
Ich habe diesen Code in einem RailsCast gefunden :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
Was bedeutet das (&:name)in map(&:name)?
Antworten:
Es ist eine Abkürzung für tags.map(&:name.to_proc).join(' ')
Wenn fooes sich um ein Objekt mit einer to_procMethode handelt, können Sie es an eine Methode als übergeben &foo, die diese aufruft foo.to_procund als Block der Methode verwendet.
Die Symbol#to_procMethode wurde ursprünglich von ActiveSupport hinzugefügt, wurde jedoch in Ruby 1.8.7 integriert. Dies ist seine Umsetzung:
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
&, dhtags.map(&:name.to_proc).join(' ')
Eine andere coole Abkürzung, die vielen unbekannt ist, ist
array.each(&method(:foo))
Das ist eine Abkürzung für
array.each { |element| foo(element) }
Durch Aufrufen haben method(:foo)wir ein MethodObjekt genommen self, das seine fooMethode darstellt, und das verwendet, &um anzuzeigen, dass es eine to_proc Methode hat , die es in eine konvertiert Proc.
Dies ist sehr nützlich, wenn Sie einen punktfreien Stil ausführen möchten . Ein Beispiel ist die Überprüfung, ob ein Array eine Zeichenfolge enthält, die der Zeichenfolge entspricht "foo". Es gibt den herkömmlichen Weg:
["bar", "baz", "foo"].any? { |str| str == "foo" }
Und da ist der punktfreie Weg:
["bar", "baz", "foo"].any?(&"foo".method(:==))
Der bevorzugte Weg sollte der am besten lesbare sein.
array.each{|e| foo(e)}ist noch kürzer :-) +1 sowieso
&method?
[1,2,3].map(&Array.method(:new))
Es ist gleichbedeutend mit
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
Beachten wir auch, dass kaufmännisches Und-Zeichen- #to_procMagie mit jeder Klasse funktionieren kann, nicht nur mit Symbol. Viele Rubyisten definieren die #to_procArray-Klasse wie folgt :
class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
Das kaufmännische Und &sendet eine to_procNachricht an seinen Operanden, der im obigen Code zur Array-Klasse gehört. Und da ich die #to_procMethode für das Array definiert habe , wird die Zeile wie folgt:
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
Es ist eine Abkürzung für tags.map { |tag| tag.name }.join(' ')
&ruft der unäre Operator to_procseinen Operanden auf. Es ist also nicht spezifisch für die Map-Methode und funktioniert tatsächlich mit jeder Methode, die einen Block nimmt und ein oder mehrere Argumente an den Block übergibt.
tags.map(&:name)
ist das gleiche wie
tags.map{|tag| tag.name}
&:name verwendet nur das Symbol als den aufzurufenden Methodennamen.
Josh Lees Antwort ist fast richtig, außer dass der entsprechende Ruby-Code wie folgt lauten sollte.
class Symbol
def to_proc
Proc.new do |receiver|
receiver.send self
end
end
end
nicht
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Wenn dieser Code print [[1,'a'],[2,'b'],[3,'c']].map(&:first)ausgeführt wird, teilt Ruby die erste Eingabe [1,'a']in 1 und 'a' auf, um obj1 zu geben, und args*'a', um einen Fehler zu verursachen, da das Fixnum-Objekt 1 nicht über die Methode self verfügt (dh: first).
Wann [[1,'a'],[2,'b'],[3,'c']].map(&:first)wird ausgeführt;
:firstist ein Symbol-Objekt. Wenn &:firstalso eine Map-Methode als Parameter angegeben wird, wird Symbol # to_proc aufgerufen.
map sendet eine Aufrufnachricht an: first.to_proc mit Parameter [1,'a'], zB :first.to_proc.call([1,'a'])wird ausgeführt.
Die Prozedur to_proc in der Symbolklasse sendet eine Sende-Nachricht an ein Array-Objekt ( [1,'a']) mit dem Parameter (: first), z [1,'a'].send(:first). B. wird ausgeführt.
iteriert über den Rest der Elemente im [[1,'a'],[2,'b'],[3,'c']]Objekt.
Dies ist dasselbe wie das Ausführen eines [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)Ausdrucks.
[1,2,3,4,5,6].inject(&:+), dass Inject ein Lambda mit zwei Parametern (Memo und Item) erwartet und es :+.to_procliefert - Proc.new |obj, *args| { obj.send(self, *args) }oder{ |m, o| m.+(o) }
Hier passieren zwei Dinge, und es ist wichtig, beide zu verstehen.
Wie in anderen Antworten beschrieben, wird die Symbol#to_procMethode aufgerufen.
Der Grund to_proc, warum das Symbol aufgerufen wird, ist, dass es mapals Blockargument übergeben wird. Wenn Sie &in einem Methodenaufruf vor einem Argument stehen, wird es auf diese Weise übergeben. Dies gilt für jede Ruby-Methode, nicht nur mapfür Symbole.
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)
Das Symbolwird in a konvertiert, Procweil es als Block übergeben wird. Wir können dies zeigen, indem wir versuchen, einen Proc .mapohne kaufmännisches Und weiterzugeben :
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"]
Obwohl es nicht konvertiert werden muss, weiß die Methode nicht, wie es verwendet werden soll, da sie ein Blockargument erwartet. Passen Sie es mit &gibt .mapden Block , es erwartet.
map (&: name) verwendet ein aufzählbares Objekt (in Ihrem Fall Tags) und führt die Namensmethode für jedes Element / Tag aus, wobei jeder zurückgegebene Wert von der Methode ausgegeben wird.
Es ist eine Abkürzung für
array.map { |element| element.name }
Dies gibt das Array der Elementnamen (Tag-Namen) zurück
Grundsätzlich wird der Methodenaufruf tag.namefür jedes Tag im Array ausgeführt.
Es ist eine vereinfachte Rubin-Abkürzung.
Obwohl wir bereits gute Antworten haben, möchte ich aus der Perspektive eines Anfängers die zusätzlichen Informationen hinzufügen:
Was bedeutet map (&: name) in Ruby?
Dies bedeutet, dass Sie eine andere Methode als Parameter an die Kartenfunktion übergeben. (In Wirklichkeit übergeben Sie ein Symbol, das in einen Proc umgewandelt wird. Dies ist jedoch in diesem speziellen Fall nicht so wichtig.)
Wichtig ist, dass Sie einen methodNamen haben name, der von der Map-Methode als Argument anstelle des traditionellen blockStils verwendet wird.
Zuerst, &:name ist dies eine Verknüpfung für &:name.to_proc, bei :name.to_procder ein Proc(etwas, das einem Lambda ähnlich, aber nicht identisch ist) zurückgegeben wird, das beim Aufrufen mit einem Objekt als (erstem) Argument die nameMethode für dieses Objekt aufruft .
Zweitens während & in def foo(&block) ... endwandelt ein Block zu übergeben , fooum einen Proc, sie tut das Gegenteil , wenn sie einen aufgebracht Proc.
Es handelt sich also &:name.to_procum einen Block, der ein Objekt als Argument verwendet und die nameMethode dafür aufruft , d { |o| o.name }. H.
Es ist das gleiche wie unten:
def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end