Saya mencoba memahami blok yield
dan cara kerjanya di Ruby.
Bagaimana yield
digunakan? Banyak aplikasi Rails yang saya lihat digunakan yield
dengan cara yang aneh.
Bisakah seseorang menjelaskan kepada saya atau menunjukkan kepada saya ke mana harus pergi untuk memahaminya?
Jawaban:
Ya, pada awalnya agak membingungkan.
Di Ruby, metode dapat menerima blok kode untuk melakukan segmen kode yang sewenang-wenang.
Ketika metode mengharapkan blok, ia memanggilnya dengan memanggil
yield
fungsi.Ini sangat berguna, misalnya, untuk mengulangi daftar atau untuk menyediakan algoritma kustom.
Ambil contoh berikut:
Saya akan mendefinisikan
Person
kelas yang diinisialisasi dengan nama, dan memberikando_with_name
metode yang ketika dipanggil, hanya akan meneruskanname
atribut, ke blok yang diterima.Ini akan memungkinkan kami untuk memanggil metode itu dan melewati blok kode arbitrer.
Misalnya, untuk mencetak nama yang akan kita lakukan:
Akan mencetak:
Perhatikan, blok menerima, sebagai parameter, variabel yang disebut
name
(NB Anda dapat memanggil variabel ini apa pun yang Anda suka, tetapi masuk akal untuk menyebutnyaname
). Ketika kode memanggilyield
itu mengisi parameter ini dengan nilai@name
.Kami dapat menyediakan blok lain untuk melakukan tindakan yang berbeda. Misalnya, balikkan nama:
Kami menggunakan metode yang persis sama (
do_with_name
) - itu hanya blok yang berbeda.Contoh ini sepele. Penggunaan yang lebih menarik adalah memfilter semua elemen dalam array:
Atau, kami juga dapat menyediakan algoritme pengurutan khusus, misalnya berdasarkan ukuran string:
Saya harap ini membantu Anda untuk memahaminya dengan lebih baik.
BTW, jika bloknya opsional Anda harus menyebutnya seperti:
Jika tidak opsional, aktifkan saja.
EDIT
@hmak membuat repl.it untuk contoh-contoh ini: https://repl.it/@makstaks/blocksandyieldsrubyexample
sumber
racsO
jikathe_name = ""
"Oscar"
(tidak begitu jelas dalam jawabannya)person.do_with_name {|string| yield string, something_else }
Di Ruby, metode dapat memeriksa untuk melihat apakah mereka dipanggil sedemikian rupa sehingga blok diberikan selain argumen normal. Biasanya ini dilakukan dengan menggunakan
block_given?
metode tetapi Anda juga bisa merujuk ke blok sebagai Proc eksplisit dengan awalan sebuah ampersand (&
) sebelum nama argumen terakhir.Jika suatu metode dipanggil dengan sebuah blok maka metode tersebut dapat
yield
mengontrol ke blok (panggil blok) dengan beberapa argumen, jika diperlukan. Pertimbangkan contoh metode ini yang menunjukkan:Atau, menggunakan sintaks argumen blok khusus:
sumber
Sangat mungkin bahwa seseorang akan memberikan jawaban yang benar-benar terperinci di sini, tetapi saya selalu menemukan posting ini dari Robert Sosinski sebagai penjelasan yang bagus tentang seluk-beluk antara blok, procs & lambdas.
Saya harus menambahkan bahwa saya yakin posting yang saya tautkan khusus untuk ruby 1.8. Beberapa hal telah berubah di ruby 1.9, seperti variabel blok menjadi lokal ke blok. Di 1.8, Anda akan mendapatkan sesuatu seperti berikut:
Sedangkan 1,9 akan memberi Anda:
Saya tidak memiliki 1,9 pada mesin ini sehingga di atas mungkin ada kesalahan di dalamnya.
sumber
Saya ingin semacam menambahkan mengapa Anda melakukan hal-hal seperti itu untuk jawaban yang sudah bagus.
Tidak tahu bahasa apa yang Anda gunakan, tetapi dengan asumsi itu adalah bahasa statis, hal semacam ini akan terlihat familier. Ini adalah bagaimana Anda membaca file dalam java
Mengabaikan hal-hal yang mengalir secara keseluruhan, Idenya adalah ini
Ini adalah bagaimana Anda melakukannya di ruby
Sangat berbeda. Hancurkan yang ini
Di sini, alih-alih menangani langkah satu dan dua, Anda pada dasarnya mendelegasikannya ke kelas lain. Seperti yang Anda lihat, itu secara dramatis menurunkan jumlah kode yang harus Anda tulis, yang membuat hal-hal lebih mudah dibaca, dan mengurangi kemungkinan hal-hal seperti kebocoran memori, atau kunci file tidak dibersihkan.
Sekarang, ini tidak seperti Anda tidak dapat melakukan sesuatu yang serupa di java, pada kenyataannya, orang telah melakukannya selama beberapa dekade sekarang. Ini disebut pola Strategi . Perbedaannya adalah bahwa tanpa blok, untuk sesuatu yang sederhana seperti contoh file, strategi menjadi berlebihan karena jumlah kelas dan metode yang perlu Anda tulis. Dengan blok, ini adalah cara yang sangat sederhana dan elegan untuk melakukannya, sehingga tidak masuk akal untuk tidak menyusun kode seperti itu.
Ini bukan satu-satunya cara blok digunakan, tetapi yang lain (seperti pola Builder, yang dapat Anda lihat di form_for api in rails) cukup mirip sehingga harus jelas apa yang terjadi setelah Anda membungkus kepala Anda di sekitar ini. Ketika Anda melihat blok, biasanya aman untuk mengasumsikan bahwa pemanggilan metode adalah apa yang ingin Anda lakukan, dan blok tersebut menggambarkan bagaimana Anda ingin melakukannya.
sumber
File.readlines("readfile.rb").each_with_index do |line, index| puts "#{index + 1}: #{line}" end
dan tertawa lebih keras pada orang-orang Jawa.IO.foreach('readfile.rb').each_with_index { |line, index| puts "#{index}: #{line}" }
(ditambah tidak ada masalah memori)Saya menemukan artikel ini sangat berguna. Secara khusus, contoh berikut:
yang akan menghasilkan output sebagai berikut:
Jadi intinya setiap kali panggilan dibuat ke
yield
ruby akan menjalankan kode dido
blok atau di dalam{}
. Jika parameter disediakan untukyield
ini, ini akan diberikan sebagai parameter untukdo
blok.Bagi saya, ini adalah pertama kalinya saya benar-benar mengerti apa yang dilakukan
do
balok. Ini pada dasarnya adalah cara bagi fungsi untuk memberikan akses ke struktur data internal, baik untuk iterasi atau untuk konfigurasi fungsi.Jadi ketika di rel Anda menulis yang berikut:
Ini akan menjalankan
respond_to
fungsi yang menghasilkando
blok denganformat
parameter (internal) . Anda kemudian memanggil.html
fungsi pada variabel internal ini yang pada gilirannya menghasilkan blok kode untuk menjalankanrender
perintah. Perhatikan bahwa.html
hanya akan menghasilkan jika format file yang diminta. (teknis: fungsi-fungsi ini sebenarnya digunakanblock.call
bukanyield
seperti yang Anda lihat dari sumber tetapi fungsinya pada dasarnya sama, lihat pertanyaan ini untuk diskusi.) Ini menyediakan cara bagi fungsi untuk melakukan beberapa inisialisasi kemudian mengambil input dari kode panggilan dan kemudian lanjutkan pemrosesan jika diperlukan.Atau dengan kata lain, ini mirip dengan fungsi yang mengambil fungsi anonim sebagai argumen dan kemudian memanggilnya dalam javascript.
sumber
Di Ruby, sebuah blok pada dasarnya adalah sepotong kode yang dapat diteruskan ke dan dieksekusi dengan metode apa pun. Blok selalu digunakan dengan metode, yang biasanya memasukkan data ke mereka (sebagai argumen).
Blok banyak digunakan dalam permata Ruby (termasuk Rails) dan dalam kode Ruby yang ditulis dengan baik. Mereka bukan objek, karenanya tidak dapat ditugaskan ke variabel.
Sintaks Dasar
Blok adalah bagian dari kode yang dilampirkan oleh {} atau do..end. Dengan konvensi, sintaks kurung kurawal harus digunakan untuk blok baris tunggal dan sintaks do..end harus digunakan untuk blok multisaluran.
Metode apa pun dapat menerima blok sebagai argumen implisit. Blok dieksekusi oleh pernyataan hasil dalam suatu metode. Sintaks dasarnya adalah:
Ketika pernyataan hasil tercapai, metode meditasi menghasilkan kontrol ke blok, kode di dalam blok dieksekusi dan kontrol dikembalikan ke metode, yang melanjutkan eksekusi segera setelah pernyataan hasil.
Ketika suatu metode berisi pernyataan hasil, itu diharapkan untuk menerima blok pada waktu panggilan. Jika blok tidak disediakan, pengecualian akan dilemparkan setelah pernyataan hasil tercapai. Kami dapat membuat blok opsional dan menghindari pengecualian yang muncul:
Tidak mungkin untuk melewatkan beberapa blok ke suatu metode. Setiap metode hanya dapat menerima satu blok.
Lihat lebih lanjut di: http://www.zenruby.info/2016/04/introduction-to-blocks-in-ruby.html
sumber
Saya kadang menggunakan "hasil" seperti ini:
sumber
Logger
harus dilakukan beberapa tugas jika pengguna tidak perlu. Anda harus menjelaskan milik Anda ...Hasilkan, sederhananya, biarkan metode yang Anda buat untuk mengambil dan memanggil blok. Kata kunci hasil secara khusus adalah tempat di mana 'barang' di blok akan dilakukan.
sumber
Ada dua poin yang ingin saya sampaikan tentang hasil di sini. Pertama, sementara banyak jawaban di sini berbicara tentang berbagai cara untuk melewatkan blok ke metode yang menggunakan hasil, mari kita juga bicara tentang aliran kontrol. Ini sangat relevan karena Anda dapat menghasilkan GANDA kali ke blok. Mari kita lihat sebuah contoh:
Ketika setiap metode dipanggil, ia mengeksekusi baris demi baris. Sekarang ketika kita sampai ke blok 3.times, blok ini akan dipanggil 3 kali. Setiap kali ia meminta hasil. Hasil itu terkait dengan blok yang terkait dengan metode yang disebut metode masing-masing. Penting untuk memperhatikan bahwa setiap hasil waktu dipanggil, ia mengembalikan kontrol ke blok masing-masing metode dalam kode klien. Setelah blok selesai dieksekusi, ia kembali ke blok 3.times. Dan ini terjadi 3 kali. Sehingga blok dalam kode klien dipanggil pada 3 kesempatan terpisah karena hasil secara eksplisit disebut 3 waktu terpisah.
Poin kedua saya adalah tentang enum_for dan hasil. enum_for instantiates kelas Enumerator dan objek Enumerator ini juga merespons untuk menghasilkan.
Jadi perhatikan setiap kali kita memohon jenis dengan iterator eksternal, itu akan memanggil hasil hanya sekali. Lain kali kita menyebutnya, itu akan memanggil hasil berikutnya dan seterusnya.
Ada berita menarik yang menarik sehubungan dengan enum_for. Dokumentasi online menyatakan sebagai berikut:
Jika Anda tidak menentukan simbol sebagai argumen untuk enum_for, ruby akan menghubungkan enumerator ke masing-masing metode penerima. Beberapa kelas tidak memiliki metode masing-masing, seperti kelas String.
Dengan demikian, dalam kasus beberapa objek yang dipanggil dengan enum_for, Anda harus secara eksplisit mengenai apa metode penghitungan Anda nantinya.
sumber
Hasil dapat digunakan sebagai blok tanpa nama untuk mengembalikan nilai dalam metode. Pertimbangkan kode berikut:
Anda dapat membuat metode "Atas" yang diberikan satu argumen. Anda sekarang dapat menetapkan argumen ini untuk menghasilkan yang akan memanggil dan mengeksekusi blok terkait. Anda dapat menetapkan blok setelah daftar parameter.
Ketika metode Naik memanggil hasil, dengan argumen, itu diteruskan ke variabel blok untuk memproses permintaan.
sumber