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 fooobjek dengan to_procmetode, maka Anda bisa meneruskannya ke metode sebagai &foo, yang akan memanggil foo.to_procdan menggunakannya sebagai blok metode.
The Symbol#to_procMetode 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 Methodobjek dari selfyang mewakili foometodenya, 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_procmagic dapat bekerja dengan semua kelas, bukan hanya Symbol. Banyak Rubyist memilih untuk mendefinisikan #to_procpada 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_procpesan pada operannya, yang, dalam kode di atas, adalah dari kelas Array. Dan karena saya mendefinisikan #to_procmetode pada Array, barisnya menjadi:
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
Ini singkatan untuk tags.map { |tag| tag.name }.join(' ')
&operator unary memanggil to_procoperannya. 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 obj1 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;
:firstadalah objek Simbol, jadi ketika &:firstdiberikan 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_procmengirimkannya - 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_procmetode ini dipanggil.
Tapi alasannya to_procdipanggil pada simbol adalah karena dilewatkan mapsebagai argumen blok. Menempatkan &di depan argumen dalam pemanggilan metode menyebabkannya diteruskan dengan cara ini. Ini berlaku untuk metode Ruby apa pun, tidak hanya mapdengan 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 Symboldikonversi ke Prockarena dilewatkan sebagai blok. Kami dapat menunjukkan ini dengan mencoba meneruskan proc ke .maptanpa 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 .mapblok 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.namepada 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 methodnama nameyang akan digunakan oleh metode peta sebagai argumen alih-alih blockgaya tradisional .
Pertama, &:nameadalah jalan pintas untuk &:name.to_proc, di mana :name.to_procmengembalikan Proc(sesuatu yang mirip, tetapi tidak identik dengan lambda) yang ketika dipanggil dengan objek sebagai argumen (pertama), memanggil namemetode pada objek itu.
Kedua, sementara &di def foo(&block) ... endmualaf blok diteruskan ke fooke Proc, itu tidak sebaliknya bila diterapkan pada Proc.
Dengan demikian, &:name.to_procadalah blok yang mengambil objek sebagai argumen dan memanggil namemetode 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