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 ยกเลิกหลายระดับของการควบคุมการไหลเช่นวงซ้อนกันสามารถทำได้ด้วยreturnthrow
ในขณะที่กลไกการยกเว้นของการยกและช่วยเหลือดีเยี่ยมสำหรับการละทิ้งการปฏิบัติเมื่อสิ่งต่าง ๆ ผิดพลาดบางครั้งก็ดีที่สามารถกระโดดออกจากโครงสร้างที่ซ้อนกันอย่างลึกล้ำระหว่างการประมวลผลปกติ นี่คือที่จับและโยนเข้ามามีประโยชน์ (โทมัสและล่า, 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 จะจับเท่านั้นFoocatch(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
ในขณะที่หลายcatches จะต้องซ้อนกัน ...
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 มีข้อเสนอที่ถูกปฏิเสธสำหรับเรื่องนี้)