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 foo
bir ile bir nesnedir to_proc
yöntemle, o zaman gibi bir yönteme geçirebilirsiniz &foo
arayacak foo.to_proc
ve yöntemin bloğu olarak kullanılması söyledi.
Symbol#to_proc
Yö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 Method
nesneyi aldık ve onu bir nesnesine dönüştüren bir yöntemi olduğunu belirtmek için kullandık .self
foo
&
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_proc
bü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_proc
Array ü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_proc
operandı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 obj
1 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;
:first
bir Symbol nesnesidir, bu nedenle &:first
bir 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_proc
sunar - 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_proc
sembolün üzerinde durulması nedeni , map
blok 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 map
sembollerle 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 Symbol
için dönüştürülür Proc
. .map
Ve 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.name
dizideki 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 method
adında name
yerine geleneksel bir argüman olarak harita yöntemiyle kullanılan olacağını block
tarzı.
İlk olarak, &:name
bir kısayol &:name.to_proc
, burada :name.to_proc
dö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) name
bu nesne ile ilgili bir yöntem.
İkinci olarak, &
içinde def foo(&block) ... end
dönüştürür bir blok geçirilen foo
bir için Proc
, bir tatbik tersini yapar Proc
.
Böylece, &:name.to_proc
bir 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