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

ช่วยชีวิตเคล็ดลับอันสง่างามเพื่อรู้ว่าข้อยกเว้นใดที่ควรจับ

หากคุณเคยทำงานกับข้อยกเว้นของ Ruby มาก่อน คุณจะรู้ว่าคุณสามารถระบุได้ว่าข้อยกเว้นใดจะได้รับการช่วยเหลือและข้อยกเว้นใดบ้าง:

begin
  raise ArgumentError
rescue ArgumentError
  # Rescues the `ArgumentError`
end

...และคุณอาจรู้ว่าเมื่อคุณช่วย "พ่อแม่" คุณก็ช่วย "ลูกๆ" ของมันด้วยเช่นกัน

begin 
  raise ArgumentError
rescue StandardError
  # Rescues `ArgumentError`, because it inherits from 
  # `StandardError`
end

เมื่อฉันพูดว่า "parent" และ "child" ฉันหมายถึงการสืบทอดคลาส ลึกลงไปในซอร์สโค้ดของ Ruby มีบางสิ่งที่เทียบเท่ากับสิ่งนี้:

class ArgumentError < StandardError
   ...
end

เคล็ดลับที่น่าสนใจ

นี่คือคำถามของฉัน:Ruby จะรู้ได้อย่างไรว่าข้อยกเว้นที่ได้รับมาจากคลาสที่คุณระบุหรือไม่

แนวทางที่ชัดเจนที่สุดคือการใช้ is_a? หรือ kind_of? กระบวนการ. เราสามารถจินตนาการว่ามันมีลักษณะเช่นนี้:

if the_exception.is_a?(StandardError)
   # do the rescue
end

แต่นั่นไม่ใช่สิ่งที่เกิดขึ้น Ruby ใช้ === . ที่น่าสนใจกว่าแทน โอเปอเรเตอร์

if StandardError === the_exception
   # do the rescue
end

หากคุณไม่เคยใช้ a === b มักจะตอบคำถามว่า "a อยู่ในกลุ่มที่กำหนดโดย b" หรือไม่? นี่คือตัวอย่างบางส่วน:

(1..10) === 5             # true
('a'..'f') === "z"        # false

String === "hello"        # true
String === 1              # false

/[0-9]{3}/ === "hello123" # true
/[0-9]{3}/ === "hello"    # false

เพราะ === เป็นเพียงวิธีการทับทิมธรรมดาๆ เช่น == เราสามารถกำหนดได้เอง:

class RedThings
   def self.===(thing)
     thing.color == :red
   end
end

แล้วเรารู้อะไรบ้าง? เรารู้ว่า rescue ใช้ === เพื่อกำหนดข้อยกเว้นที่จะได้รับการช่วยเหลือ และเรารู้ว่าเราสามารถกำหนด === . ของเราเองได้ กระบวนการ. นั่นหมายความว่าเราสามารถสร้างชั้นเรียนที่ตัดสินใจได้ทันทีว่าข้อยกเว้นใดบ้างที่ได้รับการช่วยเหลือ:

class SevereMatcher
  def self.===(exception)
    exception.message =~ /severe/    
  end
end

begin
  raise RuntimeError, "Something severe happened"
rescue SevereMatcher
  # rescues all exceptions with the word "severe" in
  # the message, regardless of class.
end

เมื่อคุณรู้เคล็ดลับนี้แล้ว ขีดจำกัดเพียงอย่างเดียวคือจินตนาการของคุณ

บทสรุป

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