Лови и кидай в кастом исключения - PullRequest
6 голосов
/ 21 сентября 2019

Должен ли 'CATCH' вызываться строго после 'throw'?

Пример 1:

say 'Hello World!';

class E is Exception { method message() { "Just stop already!" } }

CATCH {
    when E {
            .resume;
    }
}

E.new.throw;

Ошибка:

Не удается найти «приемник» метода: нет кэша метода и нет. ^ Find_method в блоке в строке /tmp/739536251/main.pl6 11

Пример 2:

say 'Hello World!';

class E is Exception { method message() { "Just stop already!" } }

E.new.throw;

CATCH {
    when E {
            .resume;
    }
}

Нет ошибок

Ответы [ 2 ]

4 голосов
/ 21 сентября 2019

CATCH должен быть в том же блоке.

Проблема в первом примере состоит в том, что нет E, но выдается другое исключение.Попробуйте

class E is Exception { method message() { "Just stop already!" } };

CATCH {
    when E {
        .resume;
    }
    default { say .perl }
}

E.new.throw;

, вы можете изменить when block

class E is Exception { method message() { "Just stop already!" } };

CATCH {
    when E {
        say .message;
    }
}

E.new.throw;

или определение класса E, например,

class E is Exception { 
    has $.resume; 
    method message() { "Just stop already!" } 
};

CATCH {
    when E {
        say .resume;
    }
}

E.new(resume => 'stop here').throw;
3 голосов
/ 22 сентября 2019

Это уже поданная .resume ошибка .


Сообщение об ошибке не самое удивительное, которое когда-либо производил P6, но технически оно не LTA потому что он описательный и связан с ошибкой (вызванной ошибкой).


CATCH и выбрасывание пользовательского исключения

Я думаю, что это просто.resume ошибка, а не о пользовательских исключениях.

Должен ли 'CATCH' вызываться строго после 'throw'?

Нет, это не проблема.(Тем не менее, поместив его после .throw просто так, чтобы избежать этой ошибки; я вернусь к этому позже.)


В коде, который идет бум, вы бросаете исключение, затем.resume в ответ на это.Согласно документу .resume:

Возобновляет поток управления, где .throw оставил его

Что в данном случае означает, куда указывает стрелка:

E.new.throw ;
           ?

Теперь рассмотрим эту программу:

42;

Если вы запустите эту программу, вы увидите:

Useless use of constant integer 42 in sink context (line 1)

Это потому, что P6 применяет "контекст приемника" правила при принятии решения, что делать в конце заявления.Применение контекста приемника влечет за собой вызов .sink для значения, созданного оператором.А для 42 метод .sink генерирует «бесполезное» предупреждение.

Но каково значение .resume d брошенного исключения?

class E is Exception {}
CATCH { when E { .resume } }
say E.new.throw.^name; # BOOTException
E.new.throw.sink;      # Cannot find method 'sink': no method cache and no .^find_method

Оказывается, этоBOOTException объект, который не является объектом высокого уровня P6, но является объектом низкого уровня VM, объект, у которого нет метода .sink (а также блокирует резервные методы P6 для нахождения метода, следовательно, «Я перепробовал все»"сообщение об ошибке).


Так почему же установка CATCH block после throw имеет значение?

Кажется, ошибка возникает, только еслиоператор throw является оператором last .Это прекрасно работает, просто отображая 42:

class E is Exception {}
CATCH { when E { .resume } }
E.new.throw;
say 42;

Как вы, вероятно, знаете, P6 обрабатывает последний оператор блока специально.Возможно, эта ошибка связана с этим.

...