"Keluar dari loop bersarang" adalah kebutuhan umum dalam banyak bahasa pemrograman. Selain gotodi C / C ++ seperti @docwhat telah disebutkan, Java telah memberi label break dan continue . (Python juga memiliki proposal yang ditolak untuk ini.)
menangkap / melempar tidak sama dengan menaikkan / menyelamatkan. catch / throw memungkinkan Anda untuk dengan cepat keluar dari blok kembali ke titik di mana tangkapan didefinisikan untuk simbol tertentu, meningkatkan penyelamatan adalah pengecualian nyata yang menangani hal-hal yang melibatkan objek Pengecualian.
Penasaran ingin tahu ... Membaca ini dari iPad, jadi tidak bisa mengujinya di 1.9, tetapi beberapa gotcha itu tidak lagi berlaku di versi ruby terbaru, kan?
Denis de Bernardy
12
Juga perlu diketahui: raisesangat mahal. throwtidak. Anggap throwsebagai menggunakan gotountuk keluar dari lingkaran.
raise, fail, rescue, Dan ensuremenangani kesalahan , juga dikenal sebagai pengecualian
throwdan catchyang aliran kontrol
Tidak seperti dalam bahasa lain, lemparan dan tangkapan Ruby tidak digunakan untuk pengecualian. Sebaliknya, mereka menyediakan cara untuk menghentikan eksekusi lebih awal ketika tidak ada pekerjaan lebih lanjut diperlukan. (Grimm, 2011)
Mengakhiri satu tingkat aliran kontrol, seperti whileloop, dapat dilakukan dengan sederhana return. Mengakhiri banyak level aliran kontrol, seperti loop bersarang, dapat dilakukan dengan throw.
Meskipun mekanisme pengecualian untuk meningkatkan dan menyelamatkan sangat bagus untuk mengabaikan eksekusi ketika ada kesalahan, terkadang bagus untuk dapat melompat keluar dari beberapa konstruksi yang bersarang selama pemrosesan normal. Di sinilah menangkap dan melempar berguna. (Thomas and Hunt, 2001)
raiseSaya rescueadalah analog terdekat dengan throw/ catchkonstruksi yang Anda kenal dari bahasa lain (atau ke Python raise/ except). Jika Anda mengalami kondisi kesalahan dan Anda akan throwmemperbaikinya dalam bahasa lain, Anda harus raisemenggunakan Ruby.
Ruby throw/ catchmemungkinkan Anda menghentikan eksekusi dan memanjat tumpukan mencari catch(seperti raise/ rescuetidak), tetapi tidak dimaksudkan untuk kondisi kesalahan. Ini harus jarang digunakan, dan apakah ada hanya ketika "berjalan tumpukan sampai Anda menemukan yang sesuai catch" perilaku masuk akal untuk algoritma yang Anda tulis tetapi tidak masuk akal untuk memikirkan yang throwsesuai dengan kesalahan kondisi.
Perbedaan perilaku konkret di antara mereka termasuk:
rescue Fooakan menyelamatkan instance dari Footermasuk subclass dari Foo. catch(foo)hanya akan menangkap objek yang samaFoo ,. Anda tidak hanya tidak dapat memberikan catchnama kelas untuk menangkap contohnya, tetapi bahkan tidak akan melakukan perbandingan kesetaraan. Misalnya
catch("foo")do
throw "foo"end
akan memberi Anda UncaughtThrowError: uncaught throw "foo"(atau ArgumentErrorversi Ruby sebelum 2.2)
Beberapa klausul penyelamatan dapat dicantumkan ...
begin
do_something_error_pronerescueAParticularKindOfError# Insert heroism here.rescue
write_to_error_log
raiseend
sementara beberapa catches perlu disarangkan ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_barendend
Telanjang rescuesetara dengan rescue StandardErrordan merupakan konstruksi idiomatis. "Telanjang catch", seperti catch() {throw :foo}, tidak akan pernah menangkap apa pun dan tidak boleh digunakan.
Penjelasan yang baik tetapi menimbulkan pertanyaan, mengapa mereka merancang kenaikan gaji dalam ruby = melempar dalam bahasa lain. dan kemudian juga termasuk melempar tetapi! = melempar dalam bahasa lain. Saya tidak dapat melihat logika asli mereka di sana
wired00
@ wired00 (Shrug.) Saya setuju bahwa tampaknya cukup eksentrik dibandingkan dengan bahasa populer lainnya saat ini.
Mark Amery
2
@ wired00: Ini telah disebut "meningkatkan" pengecualian sejak percobaan pertama dengan penanganan kesalahan terstruktur pada 1960-an, itu disebut "meningkatkan" pengecualian dalam artikel mani yang menemukan bentuk modern dari penanganan pengecualian, disebut "meningkatkan" pengecualian dalam Lisps dan Smalltalks, yang merupakan beberapa inspirasi utama untuk Ruby, dan itu disebut "meningkatkan" pengecualian atau "meningkatkan" interupsi dalam perangkat keras, di mana konsep itu ada bahkan sebelum konsep pemrograman " bahasa "ada Pertanyaannya seharusnya adalah: mengapa bahasa-bahasa lain itu mengubahnya?
Jörg W Mittag
@MarkAmery: Ingatlah bahwa banyak dari "bahasa populer lainnya" itu lebih muda dari Ruby atau setidaknya kontemporer. Jadi, pertanyaannya seharusnya: mengapa bahasa-bahasa lain itu tidak mengikuti Ruby (dan Smalltalk dan Lisp dan perangkat keras dan literatur).
Jörg W Mittag
@ JörgWMittag Menarik - Anda mengilhami saya untuk melakukan sedikit riset sejarah. C ++ memiliki gagasan "melempar" pengecualian tahun sebelum Ruby datang, dan per english.stackexchange.com/a/449209/73974 istilah tersebut sebenarnya kembali ke tahun 70-an ... jadi saya pikir kita masih bisa mengkritik Ruby untuk mengambil terminologi yang sudah ada dan menggunakannya untuk berarti sesuatu yang sama sekali berbeda.
goto
di C / C ++ seperti @docwhat telah disebutkan, Java telah memberi label break dan continue . (Python juga memiliki proposal yang ditolak untuk ini.)Jawaban:
Saya pikir http://hasno.info/ruby-gotchas-and-caveats memiliki penjelasan yang layak tentang perbedaan:
sumber
raise
sangat mahal.throw
tidak. Anggapthrow
sebagai menggunakangoto
untuk keluar dari lingkaran.raise
,fail
,rescue
, Danensure
menangani kesalahan , juga dikenal sebagai pengecualianthrow
dancatch
yang aliran kontrolMengakhiri satu tingkat aliran kontrol, seperti
while
loop, dapat dilakukan dengan sederhanareturn
. Mengakhiri banyak level aliran kontrol, seperti loop bersarang, dapat dilakukan denganthrow
.Referensi
sumber
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise menawarkan penjelasan yang luar biasa yang saya ragu bisa saya tingkatkan. Untuk meringkas, menandai beberapa contoh kode dari posting blog saat saya pergi:
raise
Sayarescue
adalah analog terdekat denganthrow
/catch
konstruksi yang Anda kenal dari bahasa lain (atau ke Pythonraise
/except
). Jika Anda mengalami kondisi kesalahan dan Anda akanthrow
memperbaikinya dalam bahasa lain, Anda harusraise
menggunakan Ruby.Ruby
throw
/catch
memungkinkan Anda menghentikan eksekusi dan memanjat tumpukan mencaricatch
(sepertiraise
/rescue
tidak), tetapi tidak dimaksudkan untuk kondisi kesalahan. Ini harus jarang digunakan, dan apakah ada hanya ketika "berjalan tumpukan sampai Anda menemukan yang sesuaicatch
" perilaku masuk akal untuk algoritma yang Anda tulis tetapi tidak masuk akal untuk memikirkan yangthrow
sesuai dengan kesalahan kondisi.Apa yang digunakan untuk menangkap dan melempar di Ruby? menawarkan beberapa saran tentang penggunaan
throw
/catch
konstruksi yang bagus.Perbedaan perilaku konkret di antara mereka termasuk:
rescue Foo
akan menyelamatkan instance dariFoo
termasuk subclass dariFoo
.catch(foo)
hanya akan menangkap objek yang samaFoo
,. Anda tidak hanya tidak dapat memberikancatch
nama kelas untuk menangkap contohnya, tetapi bahkan tidak akan melakukan perbandingan kesetaraan. Misalnyaakan memberi Anda
UncaughtThrowError: uncaught throw "foo"
(atauArgumentError
versi Ruby sebelum 2.2)Beberapa klausul penyelamatan dapat dicantumkan ...
sementara beberapa
catch
es perlu disarangkan ...Telanjang
rescue
setara denganrescue StandardError
dan merupakan konstruksi idiomatis. "Telanjangcatch
", seperticatch() {throw :foo}
, tidak akan pernah menangkap apa pun dan tidak boleh digunakan.sumber