Frage

Ich habe diesen Code in ein Railscast :

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

Was bedeutet der (&:name) in map(&:name) bedeuten?

War es hilfreich?

Lösung

Es ist eine Abkürzung für tags.map(&:name.to_proc).join(' ')

Wenn foo ein Objekt mit einem to_proc Methode ist, dann kann man es sich auf ein Verfahren, wie &foo passieren, die foo.to_proc nennen und verwenden, die als die Blockmethode.

Die Symbol#to_proc Methode wurde ursprünglich von Active hinzugefügt wurde aber 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

Andere Tipps

Eine andere kühle Kurzschrift, vielen unbekannt ist

array.each(&method(:foo))

das ist eine Abkürzung für

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

Mit dem method(:foo) Aufruf wir nahmen ein Method Objekt aus self, das seiner foo Methode darstellt, und verwenden, um den & um anzuzeigen, dass es eine to_proc hat Methode , die es in einem Proc umwandelt.

Das ist sehr nützlich, wenn man die Dinge Punkt frei Stil tun will. Ein Beispiel ist zu überprüfen, ob es eine Zeichenfolge in einem Array ist, das auf den String "foo" gleich ist. Es ist die herkömmliche Art und Weise:

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

Und es ist der Punkt, freie Art und Weise:

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

Die bevorzugte Art und Weise sollte die lesbar sein.

Es ist äquivalent zu

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

Während wir uns auch beachten, dass Ampersand #to_proc Magie mit jeder Klasse arbeiten können, nicht nur Symbol. Viele Rubyisten wählen #to_proc auf Array-Klasse zu definieren:

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

# And then...

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

Ampersand & Werke durch das Senden to_proc Nachricht auf seinem Operanden, die in dem obigen Code, der Array-Klasse ist. Und da ich #to_proc Methode auf Array definiert, die Linie wird:

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

Es ist eine Abkürzung für tags.map { |tag| tag.name }.join(' ')

tags.map(&:name)

ist die gleiche wie

tags.map{|tag| tag.name}

&:name verwendet nur das Symbol als die Methodennamen aufgerufen werden.

Josh Lee Antwort ist fast richtig, außer dass der äquivalent Ruby-Code sein sollte wie folgt.

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

Mit diesem Code, wenn print [[1,'a'],[2,'b'],[3,'c']].map(&:first) ausgeführt wird, teilt Ruby den ersten Eingang [1,'a'] in 1 und ‚a‘ obj 1 und args* ‚a‘ zu veranlassen, einen Fehler als Fixnum Objekt geben 1 nicht das Verfahren selbst hat (das ist :zuerst).


Wenn [[1,'a'],[2,'b'],[3,'c']].map(&:first) ausgeführt wird;

  1. :first ist ein Symbol Objekt, so dass, wenn &:first auf eine Karte Methode als Parameter angegeben ist, wird Symbol # to_proc aufgerufen.

  2. Karte Anruf Nachricht an sendet: first.to_proc mit Parametern [1,'a'], zum Beispiel :first.to_proc.call([1,'a']) ausgeführt.

  3. to_proc Prozedur in Symbolklasse sendet eine Nachricht senden, um ein Array-Objekt ([1,'a']) mit dem Parameter (: zuerst). Z.B. [1,'a'].send(:first) ausgeführt

  4. iteriert über den Rest der Elemente in [[1,'a'],[2,'b'],[3,'c']] Objekt.

Dies ist die gleiche wie [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first) Ausdruck ausgeführt wird.

Zwei Dinge geschehen hier, und es ist wichtig, beide zu verstehen.

Wie in anderen Antworten beschrieben, die Symbol#to_proc Methode aufgerufen wird.

Aber der Grund to_proc wird auf dem Symbol genannt wird, weil sie als Block Argument map übergeben werden werden. Platzieren & vor einem Streit in einem Methodenaufruf bewirkt, dass es auf diese Weise weitergegeben werden. Dies gilt für alle Ruby-Methode, nicht nur map mit Symbolen.

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)

Die Symbol auf einen Proc umgewandelt werden, weil es als Block übergeben wird. Wir können dies zeigen, indem sie versuchen, eine proc zu passieren, ohne den Ampersand .map:

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

Auch wenn es nicht konvertiert werden muss, weiß die Methode nicht, wie es zu benutzen, weil es ein Block-Argument erwartet. gibt es mit & Passing .map es erwartet den Block.

(&: name) ist die Abkürzung für (&: name.to_proc) es ist die gleiche wie tags.map{ |t| t.name }.join(' ')

to_proc ist in C tatsächlich umgesetzt

Obwohl wir bereits große Antworten haben, auf der Suche durch eine Perspektive eines Anfängers würde Ich mag die zusätzliche Informationen hinzuzufügen:

  

Was ist Karte (&: Name)? Bedeuten in Ruby

Das bedeutet, dass Sie eine andere Methode als Parameter an die Kartenfunktion sind vorbei. (In Wirklichkeit Sie vorbei ein Symbol, das in ein proc umgewandelt wird. Aber das ist nicht so wichtig, in diesem speziellen Fall).

Was wichtig ist, ist, dass Sie eine method namens name haben, die anstelle des traditionellen block Stil als Argument durch die Kartenmethode verwendet wird.

Karte. (&: Name) nimmt ein zählbares Objekt (Tags in Ihrem Fall) und führt die Namen Methode für jedes Element / Tag, jeden zurückgegebene Wertes von der Methode zur Ausgabe

Es ist eine Abkürzung für

array.map { |element| element.name }

, die das Array von Elementzurückgibt (tag) Namen

Hier :name ist das Symbol, das auf die Methode name von Tag-Objekt. Wenn wir &:name zu map passieren, wird es name als proc Objekt behandeln. Für kurze, tags.map(&:name) wirkt wie:

tags.map do |tag|
  tag.name
end

bedeutet

array.each(&:to_sym.to_proc)

Es besteht im Wesentlichen den Methodenaufruf tag.name in der Anordnung auf jeder Tags auszuführen.

Es ist eine vereinfachte rubin Stenografie.

Es ist die gleiche wie unter:

def tag_names
  if @tag_names
    @tag_names
  else
    tags.map{ |t| t.name }.join(' ')
end
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top