Ruby มีกลไกการยกเว้นสองแบบที่แตกต่างกัน: Throw / Catch และ Raise / Rescue
ทำไมเราถึงมีสอง
คุณควรใช้อันใดอันหนึ่งและไม่ใช่อันอื่น
Ruby มีกลไกการยกเว้นสองแบบที่แตกต่างกัน: Throw / Catch และ Raise / Rescue
ทำไมเราถึงมีสอง
คุณควรใช้อันใดอันหนึ่งและไม่ใช่อันอื่น
คำตอบ:
ฉันคิดว่าhttp://hasno.info/ruby-gotchas-and-caveatsมีคำอธิบายที่ดีเกี่ยวกับความแตกต่าง:
การจับ / โยนนั้นไม่เหมือนกับการเพิ่ม / ช่วยเหลือ catch / throw ช่วยให้คุณออกจากบล็อกได้อย่างรวดเร็วกลับไปยังจุดที่กำหนด catch สำหรับสัญลักษณ์เฉพาะการช่วยยกคือข้อยกเว้นการจัดการสิ่งของที่เกี่ยวข้องกับวัตถุ Exception
raise
มีราคาแพงมาก throw
ไม่ใช่. คิดว่าthrow
ใช้goto
เพื่อออกจากวง
raise
, fail
, rescue
และensure
จับข้อผิดพลาดที่เรียกว่าเป็นข้อยกเว้นthrow
และcatch
มีการควบคุมการไหลไม่เหมือนกับภาษาอื่น ๆ การโยนและจับของ Ruby ไม่ได้ใช้สำหรับการยกเว้น แต่พวกเขามีวิธีที่จะยุติการดำเนินการก่อนเมื่อไม่จำเป็นต้องทำงานเพิ่มเติม (Grimm, 2011)
ยกเลิกระดับเดียวของการควบคุมการไหลเช่นห่วงสามารถทำได้ด้วยความเรียบง่ายwhile
ยกเลิกหลายระดับของการควบคุมการไหลเช่นวงซ้อนกันสามารถทำได้ด้วยreturn
throw
ในขณะที่กลไกการยกเว้นของการยกและช่วยเหลือดีเยี่ยมสำหรับการละทิ้งการปฏิบัติเมื่อสิ่งต่าง ๆ ผิดพลาดบางครั้งก็ดีที่สามารถกระโดดออกจากโครงสร้างที่ซ้อนกันอย่างลึกล้ำระหว่างการประมวลผลปกติ นี่คือที่จับและโยนเข้ามามีประโยชน์ (โทมัสและล่า, 2001)
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raiseเสนอคำอธิบายที่ยอดเยี่ยมที่ฉันสงสัยว่าฉันสามารถปรับปรุงได้ ในการสรุปให้ดักจับตัวอย่างโค้ดบางส่วนจากโพสต์บล็อกเมื่อฉันไป:
raise
/ rescue
เป็นแอนะล็อกที่ใกล้เคียงที่สุดกับthrow
/ สิ่งcatch
ก่อสร้างที่คุณคุ้นเคยจากภาษาอื่น (หรือถึง Python raise
/ except
) หากคุณพบเงื่อนไขข้อผิดพลาดและคุณจะทำthrow
มันในภาษาอื่นคุณควรraise
อยู่ใน Ruby
Ruby's throw
/ catch
ให้คุณหยุดการทำงานและไต่ขึ้นไปหา stack catch
(เช่นraise
/ rescue
ทำ) แต่ไม่ได้มีไว้สำหรับเงื่อนไขข้อผิดพลาดจริงๆ มันควรจะใช้ไม่บ่อยนักและจะเกิดขึ้นเมื่อcatch
พฤติกรรม"เดินขึ้นไปบนสแต็กจนกว่าคุณจะพบพฤติกรรม" ที่เหมาะสมสำหรับอัลกอริทึมที่คุณกำลังเขียน แต่มันก็ไม่สมเหตุสมผลที่จะคิดว่าthrow
สอดคล้องกับข้อผิดพลาด เงื่อนไข.
อะไรคือการจับและโยนที่ใช้ในทับทิม? เสนอคำแนะนำบางอย่างเกี่ยวกับการใช้throw
/ catch
สร้าง
ความแตกต่างของพฤติกรรมที่เป็นรูปธรรมระหว่างพวกเขารวมถึง:
rescue Foo
จะช่วยเหลือกรณีของการรวมถึงคลาสย่อยFoo
จะจับเท่านั้นFoo
catch(foo)
วัตถุเดียวกันFoo
เท่านั้น. ไม่เพียง แต่คุณจะไม่สามารถส่งcatch
ชื่อคลาสเพื่อจับอินสแตนซ์ของมันได้ แต่จะไม่เปรียบเทียบความเท่าเทียมกัน ตัวอย่างเช่น
catch("foo") do
throw "foo"
end
จะให้ UncaughtThrowError: uncaught throw "foo"
(หรือArgumentError
รุ่น Ruby ก่อน 2.2)
สามารถแสดงรายการคำสั่งกู้ภัยหลายรายการ ...
begin
do_something_error_prone
rescue AParticularKindOfError
# Insert heroism here.
rescue
write_to_error_log
raise
end
ในขณะที่หลายcatch
es จะต้องซ้อนกัน ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
เปลือยrescue
เท่ากับrescue StandardError
และเป็นสำนวนสร้าง เช่น "เปลือยcatch
" catch() {throw :foo}
จะไม่จับอะไรเลยและไม่ควรใช้
goto
ในC / C ++เป็น @docwhat ได้กล่าวถึง, Java ได้มีป้ายกำกับแบ่งและดำเนินการต่อ (Python มีข้อเสนอที่ถูกปฏิเสธสำหรับเรื่องนี้)