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
ฉันจะขอบคุณมากถ้าคุณแบ่งปันโพสต์นี้กับเพื่อน ๆ เพื่อให้คนอื่นสามารถเห็นได้
ขอบคุณสำหรับการอ่าน!