Bu kodu bir RailsCast içinde buldum :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
Neyi (&:name)de map(&:name)ortalama?
Bu kodu bir RailsCast içinde buldum :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
Neyi (&:name)de map(&:name)ortalama?
Yanıtlar:
İçin kestirme tags.map(&:name.to_proc).join(' ')
Eğer foobir ile bir nesnedir to_procyöntemle, o zaman gibi bir yönteme geçirebilirsiniz &fooarayacak foo.to_procve yöntemin bloğu olarak kullanılması söyledi.
Symbol#to_procYöntem ilk ActiveSupport ilave edildi ancak Ruby 1.8.7 entegre edilmiştir. Bu onun uygulamasıdır:
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
&, yanitags.map(&:name.to_proc).join(' ')
Birçok kişi tarafından bilinmeyen bir başka havalı steno
array.each(&method(:foo))
ki bu bir kısayol
array.each { |element| foo(element) }
Çağırarak , yöntemini temsil eden method(:foo)bir Methodnesneyi aldık ve onu bir nesnesine dönüştüren bir yöntemi olduğunu belirtmek için kullandık .selffoo&to_proc Proc
Noktasız stil işleri yapmak istediğinizde bu çok kullanışlıdır . Bir örnek, bir dizede dizeye eşit herhangi bir dize olup olmadığını kontrol etmektir "foo". Geleneksel bir yol var:
["bar", "baz", "foo"].any? { |str| str == "foo" }
Ve anlamsız bir yol var:
["bar", "baz", "foo"].any?(&"foo".method(:==))
Tercih edilen yol en okunabilir yöntem olmalıdır.
array.each{|e| foo(e)}yine de daha kısa :-) +1 yine de
&method?
[1,2,3].map(&Array.method(:new))
Eşittir
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
Ve işareti ve #to_procbüyünün sadece Symbol ile değil, herhangi bir sınıfla çalışabileceğini de not edelim . Birçok Rubyist #to_proc, Array sınıfında tanımlamayı seçer :
class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
Ampersand , yukarıdaki kodda Array sınıfından olan işleneni üzerinde mesaj &göndererek çalışır to_proc. Ve #to_procArray üzerinde yöntem tanımladığımdan beri , çizgi şöyle olur:
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
İçin kestirme tags.map { |tag| tag.name }.join(' ')
&operatör to_procoperandını çağırıyor . Bu nedenle, harita yöntemine özgü değildir ve aslında bir blok alan ve bloğa bir veya daha fazla argüman ileten herhangi bir yöntem üzerinde çalışır.
tags.map(&:name)
aynıdır
tags.map{|tag| tag.name}
&:name sembolü çağrılacak yöntem adı olarak kullanır.
Josh Lee'nin cevabı, eşdeğer Ruby kodunun aşağıdaki gibi olması dışında neredeyse doğrudur.
class Symbol
def to_proc
Proc.new do |receiver|
receiver.send self
end
end
end
değil
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Bu kodla print [[1,'a'],[2,'b'],[3,'c']].map(&:first)yürütüldüğünde, Ruby ilk girişi [1,'a']1'e ve 'a' ya böler ve obj1 ve args*'a' hatalarına neden olur, çünkü Fixnum nesnesi 1 kendi kendine (ilk:) yöntemine sahip değildir.
Ne zaman [[1,'a'],[2,'b'],[3,'c']].map(&:first)yürütülür;
:firstbir Symbol nesnesidir, bu nedenle &:firstbir harita yöntemine parametre olarak verildiğinde, Symbol # to_proc çağrılır.
map [1,'a'], :first.to_proc.call([1,'a'])şu parametreye sahip first.to_proc öğesine çağrı mesajı gönderir , örn . yürütülür.
Symbol sınıfındaki to_proc yordamı, [1,'a'](: first) parametresiyle bir dizi nesnesine ( ) bir gönderme iletisi gönderir , örn [1,'a'].send(:first). yürütülür.
[[1,'a'],[2,'b'],[3,'c']]nesnedeki diğer öğelerin üzerinde yinelenir .
Bu, [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)ifadenin yürütülmesi ile aynıdır .
[1,2,3,4,5,6].inject(&:+)- enjekte etmek iki parametreli (not ve öğe) bir lambda bekler ve :+.to_procsunar - Proc.new |obj, *args| { obj.send(self, *args) }veya{ |m, o| m.+(o) }
Burada iki şey oluyor ve ikisini de anlamak önemlidir.
Diğer cevaplarda açıklandığı gibi, Symbol#to_proc yöntem çağrılmaktadır.
Ancak to_procsembolün üzerinde durulması nedeni , mapblok argüman olarak aktarılmasıdır . &Bir yöntem çağrısında bir argümanın önüne yerleştirilmesi , argümanın bu şekilde iletilmesine neden olur. Bu sadece mapsembollerle değil, herhangi bir Ruby yöntemi için de geçerlidir .
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)
Bir , bir blok olarak geçirildiği Symboliçin dönüştürülür Proc. .mapVe işareti olmadan bir proc geçirmeye çalışarak bunu gösterebiliriz :
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"]
Dönüştürülmesi gerekmese de, yöntem bir blok argümanı beklediğinden nasıl kullanılacağını bilemez. İle geçmek beklediği bloğu &verir .map.
Temelde tag.namedizideki her etiket üzerinde yöntem çağrısını yürütür .
Basitleştirilmiş bir yakut stenondur.
Şimdiden harika cevaplarımız olmasına rağmen, yeni başlayanların bakış açısıyla baktığımda ek bilgiler eklemek istiyorum:
Harita (&: ad) Ruby'de ne anlama geliyor?
Bu, harita işlevine parametre olarak başka bir yöntem geçirdiğiniz anlamına gelir. (Gerçekte bir proc'a dönüştürülen bir sembol geçiriyorsunuz. Ancak bu, bu özel durumda önemli değil).
Önemli olan size bir olmasıdır methodadında nameyerine geleneksel bir argüman olarak harita yöntemiyle kullanılan olacağını blocktarzı.
İlk olarak, &:namebir kısayol &:name.to_proc, burada :name.to_procdöner bir Proc(birinci) bağımsız değişken, aramaları gibi bir nesne ile arandığı zaman (benzer bir şey, ancak bir lambda özdeş olan) namebu nesne ile ilgili bir yöntem.
İkinci olarak, &içinde def foo(&block) ... enddönüştürür bir blok geçirilen foobir için Proc, bir tatbik tersini yapar Proc.
Böylece, &:name.to_procbir nesneyi argüman olarak alan ve nameüzerindeki yöntemi çağıran bir bloktur { |o| o.name }.
Aşağıdaki ile aynı:
def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end