Розрізняють виняток і збій у блоці CATCH [RAKU]


9

Ми знаємо, що несправність може бути оброблена блоком CATCH.

У наступному прикладі ми створюємо збій "AdHoc" (в іншій підпорядкуванні) і обробляємо виняток у блоці CATCH (у моєму підрозділі)

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 с.)

Тому немає прямого способу виявити це. З точки зору дизайну, ви, мабуть, не повинні бути, і ви повинні знайти інший спосіб вирішити свою проблему. А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). У разі відмови, я хочу відновити так, ніби нічого не сталося, і дозвольте решті коду (за межами CATCH) впоратися з відмовою. У моєму прикладі я не очікував, що повернута Невдача спровокує містити Виняток! Все, що я зробив - це отримати результат в $ b і перевірити його як Bool. Це, на мій погляд, не означає "використання" відмови і, отже, спрацьовування блоку CATCH! Замість цього здається, що CATCH завжди обробляє Виняток, що міститься у відмові !!
jakar

Крім того, у вашому прикладі, що стосується непрямого способу виявлення несправності, повернутий Bool (з розумної перевірки типу відмови) має значення "False". Але я очікував, що це буде "Правда"! Я щось пропустив ???
jakar

1
@jakar tryБлок передбачає прагму use fatal, яка означає, що будь-який Failureповернувся з виклику, зроблений у блоці, негайно перетворюється на виняток. Просто не використовуйте try; a CATCHможе перейти до будь-якого блоку в Раку (тому просто майте його на рівні sub). Крім того, пишіть no fatalу верхній частині tryблоку.
Джонатан Уортінгтон

А як щодо мого другого коментаря?
jakar

1
На прикладі я дав відбитки Trueна версії Ракудо, яку я маю локально. Якщо це не по-вашому, це просто доводить сенс щодо крихкості цього.
Джонатан Уортінгтон

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. У цьому tryє кілька речей, але важлива річ у тому, що він говорить Раку негайно просувати будь-яку програму Failureв її межах до винятків - а це те, що ви говорите, що не хочете. Тож найпростіше рішення просто припинити це робити.


Ця відповідь просто дослівно повторює частину пояснення jnthn (див. Зокрема коментарі, які він написав нижче своєї відповіді). Але я не був впевнений, що всі читачі помітять / зрозуміють цей аспект, і не вважав, що коментар чи відповідь на відповідь jnthn допоможуть, отже, ця відповідь.

Я написав це як відповідь громади, щоб переконатися, що я не отримаю користі від оновлень, оскільки це очевидно не гарантує цього. Якщо він отримає достатньо зворотних даних, ми просто видалимо його.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.