แยกแยะระหว่างข้อยกเว้นและความล้มเหลวในบล็อกจับ [RAKU]


9

เรารู้ว่าสามารถจัดการความล้มเหลวได้โดยบล็อกการจับ

ในตัวอย่างต่อไปนี้เราสร้างความล้มเหลว 'AdHoc' (ใน other-sub) และเราจัดการข้อยกเว้นในบล็อก CATCH (ใน my-sub)

sub my-sub {
    try {
        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;
    }
}

sub other-sub { fail 'Failure_X' }

my-sub();

ผลลัพธ์มีดังต่อไปนี้:

AdHoc Exception handled here
This was a Failure

คำถามของฉันคือ: เราจะแยกความแตกต่างระหว่างความล้มเหลวและข้อยกเว้น "ปกติ" ในบล็อก CATCH เพื่อแยกความแตกต่างระหว่างสองกรณีได้อย่างไร

คำตอบ:


12

ความสัมพันธ์ระหว่างFailureและExceptionคือ a FailureมีException- นั่นคือมันถือวัตถุยกเว้นเป็นส่วนหนึ่งของรัฐ บางสิ่งเช่นนี้

class Failure {
    has Exception $.exception;
    # ...
}

เมื่อFailure"ระเบิด" มันจะทำเช่นนั้นโดยการโยนสิ่งExceptionที่อยู่ข้างใน ดังนั้นสิ่งที่มาถึงCATCHบล็อกคือExceptionวัตถุและไม่มีลิงก์กลับไปที่สิ่งที่แนบFailureมา (อันที่จริงแล้วExceptionวัตถุที่ให้ไว้ในหลักการสามารถเก็บรักษาได้โดยหลายคนFailure)

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

เพื่อความสมบูรณ์ผมจะทราบว่ามีเป็นวิธีทางอ้อมที่หนึ่งอาจตรวจพบว่าถูกโยนโดยException Failureตัวอย่างเช่นหากคุณได้รับ.backtraceของวัตถุข้อยกเว้นและดูแพคเกจกรอบด้านบนของมันเป็นไปได้ที่จะตรวจสอบว่ามันมาจากFailure:

sub foo() { fail X::AdHoc.new(message => "foo") }
try {
    foo();
    CATCH {
        note do { no fatal; .backtrace[0].code.package ~~ Failure };
        .resume
    }
}

อย่างไรก็ตามนี่ขึ้นอยู่กับรายละเอียดการใช้งานที่สามารถเปลี่ยนแปลงได้อย่างง่ายดายดังนั้นฉันจึงไม่พึ่งพา


เพียงเพื่อชี้แจงสิ่งที่เกิดขึ้นความตั้งใจของฉันคือการจัดการเฉพาะสำหรับข้อยกเว้น (ในบล็อกจับ) ในกรณีของความล้มเหลวฉันต้องการที่จะดำเนินการต่อราวกับว่าไม่มีอะไรเกิดขึ้นและปล่อยให้ส่วนที่เหลือของรหัส (นอก CATCH) จัดการกับความล้มเหลว ในตัวอย่างของฉันฉันไม่ได้คาดหวังความล้มเหลวที่ส่งคืนเพื่อเรียกใช้ข้อยกเว้นที่มีอยู่! ทั้งหมดที่ฉันทำคือการรับผลเป็น $ b และตรวจสอบว่าเป็นบูล ในมุมมองของฉันไม่ถือว่าเป็นการ "ใช้" ของความล้มเหลวและทำให้เกิดการบล็อก CATCH! แทนที่จะเป็นว่าดูเหมือนว่า CATCH จะจัดการกับข้อยกเว้นที่มีอยู่ในความล้มเหลวเสมอ !!
jakar

นอกจากนี้ในตัวอย่างของคุณเกี่ยวกับวิธีการตรวจจับความล้มเหลวทางอ้อม Bool ที่ส่งคืน (จากการตรวจสอบความล้มเหลวอย่างชาญฉลาด) เป็นค่า "เท็จ" แต่ฉันคาดว่ามันจะเป็น "จริง"! ฉันคิดถึงอะไรบางอย่าง ???
jakar

1
@jakar tryบล็อกหมายถึงuse fatalpragma ซึ่งหมายความว่าการFailureส่งคืนใด ๆจากการโทรในบล็อกจะถูกแปลงเป็นข้อยกเว้นทันที อย่าใช้try; a CATCHสามารถเข้าไปใน block ใด ๆ ใน Raku ได้ (เพียงแค่ให้มันอยู่ในระดับของsub) หรือเขียนno fatalที่ด้านบนของtryบล็อก
Jonathan Worthington

แล้วความคิดเห็นที่สองของฉันล่ะ
jakar

1
ใช้งานตัวอย่างที่ฉันพิมพ์Trueในเวอร์ชัน Rakudo ที่ฉันมีในเครื่อง ถ้ามันไม่ได้อยู่ที่คุณแค่พิสูจน์ให้เห็นถึงจุดอ่อนของการทำเช่นนี้
Jonathan Worthington

6

เพียงลบtryกระดาษห่อ:

sub my-sub {

#    try {              <--- remove this line...

        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;

#    }                  <--- ...and this one

}

sub other-sub { fail 'Failure_X' }

my-sub();

tryคุณใช้ A tryทำบางสิ่ง แต่สิ่งที่เกี่ยวข้องที่นี่คือการบอกให้ Raku โปรโมตใด ๆFailureในขอบเขตของข้อยกเว้น - ทันทีซึ่งเป็นสิ่งที่คุณพูดว่าคุณไม่ต้องการ ทางออกที่ง่ายที่สุดคือหยุดทำอย่างนั้น


คำตอบนี้เพียงทำซ้ำส่วนหนึ่งของคำอธิบายของ jnthn ซ้ำ ๆ (ดูความคิดเห็นเฉพาะที่เขาเขียนไว้ใต้คำตอบของเขา) แต่ฉันไม่มั่นใจว่าผู้อ่านทุกคนจะมองเห็น / เข้าใจประเด็นนี้และไม่คิดว่าความคิดเห็นหนึ่งหรือสองเกี่ยวกับคำตอบของ jnthn จะช่วยได้ดังนั้นคำตอบนี้

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.