Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Rubys Exception vs StandardError:ความแตกต่างคืออะไร?

"อย่าช่วยชีวิต Exception ใน Ruby!"

บางทีคุณอาจเคยได้ยินเรื่องนี้มาก่อน เป็นคำแนะนำที่ดี แต่ค่อนข้างสับสนเว้นแต่คุณจะรู้อยู่แล้ว เรามาทำลายคำกล่าวนี้กันและดูว่ามันหมายถึงอะไร

คุณคงรู้ว่าใน Ruby คุณสามารถกู้คืนข้อยกเว้นได้ดังนี้:

begin
  do_something()
rescue => e
  puts e # e is an exception object containing info about the error. 
end

และคุณสามารถกู้คืนข้อผิดพลาดบางอย่างได้โดยระบุชื่อคลาสของข้อผิดพลาด

begin
  do_something()
rescue ActiveRecord::RecordNotFound => e
  puts e # Only rescues RecordNotFound exceptions, or classes that inherit from RecordNotFound
end

ข้อยกเว้นทุกประเภทใน Ruby เป็นเพียงคลาส ในตัวอย่างข้างต้น ActiveRecord::RecordNotFound เป็นเพียงชื่อของคลาสที่เป็นไปตามข้อตกลงบางประการ

นี่เป็นสิ่งสำคัญเพราะเมื่อคุณช่วย RecordNotFound คุณยังช่วยเหลือข้อยกเว้นใดๆ ที่สืบทอดมาจากมัน

เหตุใดคุณจึงไม่ควรยกเว้นข้อยกเว้น

ปัญหาการช่วยเหลือ Exception คือมันช่วยทุกข้อยกเว้นที่สืบทอดมาจาก Exception . ซึ่งก็คือ....ทั้งหมดนั่นเอง!

นั่นเป็นปัญหาเนื่องจากมีข้อยกเว้นบางประการที่ Ruby ใช้ภายใน พวกเขาไม่มีส่วนเกี่ยวข้องกับแอปของคุณ และการกลืนเข้าไปจะทำให้สิ่งเลวร้ายเกิดขึ้น

นี่คือบางส่วนที่สำคัญ:

  • SignalException::Interrupt - หากคุณช่วยเหลือสิ่งนี้ คุณจะไม่สามารถออกจากแอปได้โดยกดปุ่ม control-c

  • ScriptError::SyntaxError - ข้อผิดพลาดทางไวยากรณ์การกลืนหมายความว่าสิ่งต่าง ๆ เช่น puts("Forgot something) จะล้มเหลวอย่างเงียบๆ

  • NoMemoryError - ต้องการทราบว่าจะเกิดอะไรขึ้นเมื่อโปรแกรมของคุณทำงานต่อไปหลังจากที่ใช้ RAM หมด ฉันก็เหมือนกัน

begin
  do_something()
rescue Exception => e
  # Don't do this. This will swallow every single exception. Nothing gets past it. 
end

ฉันเดาว่าคุณคงไม่อยากกลืนข้อยกเว้นระดับระบบเหล่านี้ คุณต้องการจับข้อผิดพลาดระดับแอปพลิเคชันทั้งหมดของคุณเท่านั้น ข้อยกเว้นทำให้เกิดรหัสของคุณ

โชคดีที่มีวิธีง่ายๆ ในการทำสิ่งนี้

Rescue StandardError แทน

ข้อยกเว้นทั้งหมดที่คุณควรใส่ใจเกี่ยวกับการสืบทอดจาก StandardError . นี่คือเพื่อนเก่าของเรา:

  • NoMethodError - ยกขึ้นเมื่อคุณพยายามเรียกใช้วิธีการที่ไม่มีอยู่จริง

  • TypeError - เกิดจากสิ่งต่างๆ เช่น 1 + ""

  • ข้อผิดพลาดรันไทม์ - ใครสามารถลืม RuntimeError แบบเก่าที่ดีได้

ในการแก้ไขข้อผิดพลาดเช่นนี้ คุณจะต้องกู้คืน StandardError . คุณทำได้โดยเขียนสิ่งนี้:

begin
  do_something()
rescue StandardError => e
  # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. 
end

แต่ Ruby ทำให้มันใช้งานง่ายขึ้นมาก

เมื่อคุณไม่ระบุคลาสข้อยกเว้นเลย ruby ​​จะถือว่าคุณหมายถึง StandardError ดังนั้นโค้ดด้านล่างจึงเหมือนกับโค้ดด้านบน:

begin
  do_something()
rescue => e
  # This is the same as rescuing StandardError
end

ข้อยกเว้นที่กำหนดเองควรรับช่วงต่อจาก StandardError

สิ่งนี้มีความหมายต่อคุณอย่างไรหากคุณกำลังสร้างข้อยกเว้นที่กำหนดเอง

หมายความว่าคุณควรรับช่วงต่อจาก StandardError และไม่เคยจาก Exception . การสืบทอดจากข้อยกเว้นนั้นไม่ดีเพราะเป็นการทำลายพฤติกรรมที่คาดหวังของการช่วยเหลือ ผู้คนจะคิดว่าพวกเขากำลังช่วยข้อผิดพลาดระดับแอปพลิเคชันทั้งหมด แต่ข้อผิดพลาดของคุณจะดำเนินต่อไป

class SomethingBad < StandardError
end

raise SomethingBad

ต้นไม้ข้อยกเว้น

เนื่องจากข้อยกเว้นของ Ruby ถูกนำมาใช้ในลำดับชั้นของคลาส การดูการจัดวางจึงอาจเป็นประโยชน์ ด้านล่างนี้คือรายการคลาสข้อยกเว้นที่มาพร้อมกับไลบรารีมาตรฐานของ Ruby อัญมณีของบุคคลที่สาม เช่น Rails จะเพิ่มคลาสข้อยกเว้นเพิ่มเติมให้กับแผนภูมินี้ แต่ทั้งหมดจะสืบทอดมาจากบางคลาสในรายการนี้

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit
 fatal