Saya menemukan kode ini di RailsCast :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
Apa yang (&:name)
di map(&:name)
berarti?
Saya menemukan kode ini di RailsCast :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
Apa yang (&:name)
di map(&:name)
berarti?
Jawaban:
Ini singkatan untuk tags.map(&:name.to_proc).join(' ')
Jika foo
objek dengan to_proc
metode, maka Anda bisa meneruskannya ke metode sebagai &foo
, yang akan memanggil foo.to_proc
dan menggunakannya sebagai blok metode.
The Symbol#to_proc
Metode ini awalnya ditambahkan oleh ActiveSupport tetapi telah diintegrasikan ke dalam Ruby 1.8.7. Ini implementasinya:
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
&
, yaitutags.map(&:name.to_proc).join(' ')
Steno keren lainnya, tidak diketahui banyak orang, adalah
array.each(&method(:foo))
yang merupakan singkatan untuk
array.each { |element| foo(element) }
Dengan memanggil method(:foo)
kita mengambil Method
objek dari self
yang mewakili foo
metodenya, dan menggunakan &
untuk menandakan bahwa ia memiliki to_proc
metode yang mengubahnya menjadi a Proc
.
Ini sangat berguna ketika Anda ingin melakukan hal - hal gaya point-free . Contohnya adalah untuk memeriksa apakah ada string dalam array yang sama dengan string "foo"
. Ada cara konvensional:
["bar", "baz", "foo"].any? { |str| str == "foo" }
Dan ada cara bebas-point:
["bar", "baz", "foo"].any?(&"foo".method(:==))
Cara yang disukai harus yang paling mudah dibaca.
array.each{|e| foo(e)}
masih lebih pendek :-) +1 lagian
&method
?
[1,2,3].map(&Array.method(:new))
Ini setara dengan
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
Sementara mari kita perhatikan juga bahwa ampersand #to_proc
magic dapat bekerja dengan semua kelas, bukan hanya Symbol. Banyak Rubyist memilih untuk mendefinisikan #to_proc
pada kelas Array:
class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
Ampersand &
bekerja dengan mengirim to_proc
pesan pada operannya, yang, dalam kode di atas, adalah dari kelas Array. Dan karena saya mendefinisikan #to_proc
metode pada Array, barisnya menjadi:
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
Ini singkatan untuk tags.map { |tag| tag.name }.join(' ')
&
operator unary memanggil to_proc
operannya. Jadi itu tidak spesifik untuk metode peta, dan pada kenyataannya bekerja pada metode apa pun yang mengambil blok dan melewati satu atau lebih argumen ke blok.
Jawaban Josh Lee hampir benar kecuali bahwa kode Ruby yang setara seharusnya adalah sebagai berikut.
class Symbol
def to_proc
Proc.new do |receiver|
receiver.send self
end
end
end
tidak
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Dengan kode ini, ketika print [[1,'a'],[2,'b'],[3,'c']].map(&:first)
dijalankan, Ruby membagi input pertama [1,'a']
menjadi 1 dan 'a' untuk memberikan obj
1 dan args*
'a' untuk menyebabkan kesalahan karena objek Fixnum 1 tidak memiliki metode sendiri (yaitu: pertama).
Kapan [[1,'a'],[2,'b'],[3,'c']].map(&:first)
dieksekusi;
:first
adalah objek Simbol, jadi ketika &:first
diberikan kepada metode peta sebagai parameter, Simbol # to_proc dipanggil.
map mengirim pesan panggilan ke: first.to_proc dengan parameter [1,'a']
, mis :first.to_proc.call([1,'a'])
. dijalankan.
prosedur to_proc di kelas Simbol mengirimkan pesan kirim ke objek array ( [1,'a']
) dengan parameter (: pertama), misalnya, [1,'a'].send(:first)
dijalankan.
iterates atas sisa elemen dalam [[1,'a'],[2,'b'],[3,'c']]
objek.
Ini sama dengan mengeksekusi [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)
ekspresi.
[1,2,3,4,5,6].inject(&:+)
- menyuntikkan mengharapkan lambda dengan dua parameter (memo dan item) dan :+.to_proc
mengirimkannya - Proc.new |obj, *args| { obj.send(self, *args) }
atau{ |m, o| m.+(o) }
Ada dua hal yang terjadi di sini, dan penting untuk memahami keduanya.
Seperti dijelaskan dalam jawaban lain, Symbol#to_proc
metode ini dipanggil.
Tapi alasannya to_proc
dipanggil pada simbol adalah karena dilewatkan map
sebagai argumen blok. Menempatkan &
di depan argumen dalam pemanggilan metode menyebabkannya diteruskan dengan cara ini. Ini berlaku untuk metode Ruby apa pun, tidak hanya map
dengan simbol.
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)
Akan Symbol
dikonversi ke Proc
karena dilewatkan sebagai blok. Kami dapat menunjukkan ini dengan mencoba meneruskan proc ke .map
tanpa ampersand:
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"]
Meskipun tidak perlu dikonversi, metode ini tidak akan tahu bagaimana menggunakannya karena mengharapkan argumen blok. Melewati dengan &
memberi .map
blok yang diharapkannya.
peta (&: nama) mengambil objek enumerable (memberi tag pada kasus Anda) dan menjalankan metode nama untuk setiap elemen / tag, menghasilkan setiap nilai yang dikembalikan dari metode.
Ini adalah singkatan untuk
array.map { |element| element.name }
yang mengembalikan array nama elemen (tag)
Ini pada dasarnya menjalankan pemanggilan metode tag.name
pada setiap tag dalam array.
Ini adalah steno ruby yang disederhanakan.
Meskipun kami sudah memiliki jawaban yang luar biasa, melihat melalui perspektif seorang pemula saya ingin menambahkan informasi tambahan:
Apa arti peta (&: nama) di Ruby?
Ini berarti, bahwa Anda meneruskan metode lain sebagai parameter ke fungsi peta. (Pada kenyataannya Anda melewati simbol yang akan dikonversi menjadi proc. Tapi ini tidak begitu penting dalam kasus khusus ini).
Yang penting adalah Anda memiliki method
nama name
yang akan digunakan oleh metode peta sebagai argumen alih-alih block
gaya tradisional .
Pertama, &:name
adalah jalan pintas untuk &:name.to_proc
, di mana :name.to_proc
mengembalikan Proc
(sesuatu yang mirip, tetapi tidak identik dengan lambda) yang ketika dipanggil dengan objek sebagai argumen (pertama), memanggil name
metode pada objek itu.
Kedua, sementara &
di def foo(&block) ... end
mualaf blok diteruskan ke foo
ke Proc
, itu tidak sebaliknya bila diterapkan pada Proc
.
Dengan demikian, &:name.to_proc
adalah blok yang mengambil objek sebagai argumen dan memanggil name
metode di atasnya, yaitu { |o| o.name }
.
Sama seperti di bawah ini:
def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end