Ruby จะจงใจซ่อนข้อผิดพลาดและข้อยกเว้นบางอย่างจากคุณ
บางครั้งสิ่งนี้ก็มีประโยชน์
เช่นเดียวกับเมื่อใช้ Kernel#loop เมธอดที่มีบล็อก loop จะหยุดเมื่อ StopIteration ยกข้อยกเว้นขึ้น
แต่บางครั้งอาจทำให้การดีบักของคุณยากขึ้นมาก
มาดูตัวอย่างกัน!
ข้อยกเว้นที่ซ่อนอยู่:โมดูลที่เปรียบเทียบได้ + <=> วิธีการ
ตัวอย่างแรกเกี่ยวข้องกับ Comparable โมดูล &<=> วิธีการ
นี่คือตัวอย่าง :
class MyObject
attr_accessor :value
include Comparable
def initialize(value)
@value = value
end
def <=>(other)
raise ArgumentError, "can't compare #{other.class} with #{self.class}" unless other.is_a?(MyObject)
value <=> other.valuee
end
end
mo1 = MyObject.new(10)
mo2 = MyObject.new(10)
p mo1 == mo2
มาพูดถึงตัวอย่างนี้กันดีกว่า
ก่อน :
เรามีคลาสชื่อ MyObject ด้วยหนึ่ง attr_accessor value และการรวม Comparable โมดูลซึ่งเพิ่มวิธีการเปรียบเทียบ (เช่น == , < , > ) ถึงชั้นเรียนของเรา
วิธีการเปรียบเทียบเหล่านี้ใช้ <=> วิธีการ
เช่นเดียวกับเมธอด Enumerable ที่อิงตาม each วิธีการ
แล้ว :
เรากำลังสร้างสองวัตถุ (MyObject.new ) โดยมีค่าเท่ากัน (10 )
สังเกตว่าแม้ว่าจะมีค่าเหมือนกัน เป็นวัตถุที่แตกต่างกัน , นี่เป็นสิ่งสำคัญ
ทีนี้ถ้าเราเปรียบเทียบสองวัตถุนี้ mo1 &mo2 เราได้รับ false …
ทำไม?
เนื่องจากเรามีข้อผิดพลาดใน <=> . ของเรา วิธี แต่ Ruby ซ่อนข้อผิดพลาดนั้นไว้!
ดูให้ดี…
คุณมองเห็นข้อผิดพลาดหรือไม่
หากคุณพบว่ามันเป็นงานที่ดี! ถ้าไม่ก็ไม่เป็นไร 🙂
นี่เลย :
value <=> other.valuee
ดู valuee . นี้ ?
กลายเป็นว่าเราพิมพ์ผิด!
โดยปกติเราจะได้รับ NoMethodError ข้อยกเว้น &เราจะรู้ว่าปัญหานั้นค่อนข้างเร็ว แต่ไม่ใช่ในตัวอย่างนี้
ข่าวดีก็คือตั้งแต่ Ruby 2.3 สิ่งนี้เปลี่ยนไป คุณจะเห็นข้อผิดพลาดนี้เนื่องจากไม่ได้ซ่อนไว้อีกต่อไป
อีกเหตุผลหนึ่งที่ควรอัปเกรดหากคุณยังใช้ Ruby เวอร์ชันเก่าอยู่
ข้อยกเว้นที่ซ่อนอยู่:Numeric Object + Coercion Method
อีกตัวอย่างหนึ่งของข้อยกเว้นที่ซ่อนอยู่คือ Numeric วัตถุ (Float , Integer ) บวกกับ coerce วิธีการ
นี่คือตัวอย่าง :
class MyObject
attr_accessor :value
def initialize(value)
@value = value
end
def +(other)
other = MyObject.new(other) if other.kind_of?(Numeric)
value + other.value
end
def coerce(other)
mo = MyObject.new
mo.valuee = other
[mo, self]
end
end
mo1 = MyObject.new 10
mo2 = MyObject.new 10
p mo1 + mo2
# 20
p mo1 + 20
# 30
นี่เป็นอีก MyObject class แต่ด้วยวิธีการใหม่ + &coerce .
coerce วิธีช่วยให้คุณทำงานกับสองประเภทที่เข้ากันไม่ได้และแปลงเป็นประเภทเดียวกันเพื่อให้ทำงานร่วมกันได้
ในกรณีนี้คลาสของเราจะแสดงค่าตัวเลข ซึ่งอาจเป็นจำนวนวินาที ราคา หรืออะไรทำนองนั้น…
และเราต้องการที่จะสามารถดำเนินการประเภทนี้ได้ :
mo1 + 20 20 + mo1
อันแรก (mo1 + 20 ) ง่ายเพราะเราควบคุม + วิธีการในชั้นเรียนของเรา
แต่สิ่งที่เกี่ยวกับ Integer คลาส?
เราสามารถเปลี่ยน + . ของจำนวนเต็มได้ วิธีการนี้ แต่นั่นคงไม่ใช่ความคิดที่ดี 🙂
วิธีแก้ปัญหา?
ดำเนินการ coerce วิธีการในชั้นเรียนของคุณเอง
สิ่งหนึ่งที่ + วิธีการใน Integer จะทำคือตรวจสอบว่าอ็อบเจกต์ของคุณใช้วิธีนี้หรือไม่ และถ้าเป็นเช่นนั้นก็จะเรียกมันว่า
ตอนนี้ จำตัวอย่างโค้ดที่จุดเริ่มต้นของส่วนนี้ได้หรือไม่
ถ้าเราลองทำสิ่งนี้ :
20 + mo1
เราอยากเห็น 30 เพราะค่าสำหรับ mo1 คือ 10 . แต่สิ่งที่เราเห็นคือ:
MyObject can't be coerced into Fixnum
ปัญหาเดิมๆ!
มีการซ่อนข้อผิดพลาดจากเราภายใน coerce วิธีการ
สิ่งนี้:mo.valuee = other
เรามีการพิมพ์ผิดอีกครั้ง แต่นั่นไม่ใช่สิ่งที่ผิดพลาด!
MyObject can't be coerced into Fixnum
ฉันมีข่าวดีสำหรับคุณ พฤติกรรมนี้กำลังเปลี่ยนไปใน Ruby 2.5 ดังนั้นนั่นจะเป็นอีกข้อผิดพลาดที่ซ่อนอยู่หายไป ดังนั้นคุณไม่ต้องกังวลกับมัน
สรุป
อย่างที่คุณเห็น นี่เป็นตัวอย่างที่ดีว่าทำไมคุณถึงต้องการหลีกเลี่ยงการซ่อนข้อยกเว้น คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับข้อยกเว้นในหนังสือของฉัน Ruby Deep Dive
ฉันจะขอบคุณมากถ้าคุณแบ่งปันโพสต์นี้กับเพื่อน ๆ เพื่อให้คนอื่นสามารถเห็นได้
ขอบคุณสำหรับการอ่าน!