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

Ruby กำลังซ่อนข้อผิดพลาดจากคุณ!

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

ฉันจะขอบคุณมากถ้าคุณแบ่งปันโพสต์นี้กับเพื่อน ๆ เพื่อให้คนอื่นสามารถเห็นได้

ขอบคุณสำหรับการอ่าน!