Pull to refresh

Perl6 — Обработка исключений

Reading time 4 min
Views 5.8K
1. Особенности работы с переменными и литералами в Perl6
2. Perl6 — Операции над переменными, анонимные блоки
3. Perl6 — Условные операторы, циклы
4. Perl6 — Работа с функциями
5. Perl6 — Классы
6. Perl6 — Ввод-вывод, модули
7. Perl6 — Комментарии, пробельные символы, скобки
8. Perl6 — Перегрузка операторов
9. Perl6 — Работа с типами данных
В прошлой статье я заикнулся об отлове исключений. Немногие скрипты, что встречались с исключениями, выживали, и слишком много моих скриптов погибло от их рук. Пожалуй, настало время устроить на них охоту. Для тех кому интересно, чем же мы будет их ловить — встречаемся под катом.


И так, имеем следующий кусок кода:
sub Func($a)
{
   my $temp =  $a*2;
}

Func "Test";


Как вы уже могли догадаться, мы получим исключение при попытке получить из строки «Test» десятичное число.
Чтобы добавить обработчика исключений мы должны добавить следующую конструкцию:
sub Func($a)
{
   my $temp = $a*2;
   say "Test work";

   CATCH
   {
      default
      {
          say "Something is wrong!";
      }
   }
}

Func "Test";
say "Another test work";


В отличии от того же с++, в шестом перле блок обработки исключений добавляется внутрь того блока, где может произойти исключение. Таким образом, при выполнении данного скрипта мы получим вывод:
Something is wrong!
Another test work

Иначе говоря, блок, в котором происходит исключение останавливает свою работу (и всетаки немного неправильно так говорить, но об этом поговорим потом), и начинается работа блока CATCH, в которой производится вывод строки Something is wrong. После выполнения блока CATCH скрипт продолжает выполнение начиная со следующей команды, идущей за блоком, в котором произошло исключение. Именно поэтому мы не видим на экране надписи «Test work».

Фактически, наш блок CATCH является обычным «свитчем» И мы можем добавить следующее:
sub Func($a)
{
   my $temp = $a*2;
   say "Test work";

   CATCH
   {
      when X::Syntax::Name::Null
      {
          say "I will never say it =(";
      }
      default
      {
          say "Something is wrong! "~$_.WHAT.gist;
      }
   }
}

Func "Test";
say "Another test work";

Однако текст для выбранного нами исключения гласит «Я никогда не скажу этого». Это потому что в нашем случае в функции не выполняется таких действий, в которых бы возникло данное исключение. Чтобы всетаки понять какое же исключение нам попадается, я добавил "$_.WHAT.gist". При входе в блок CATCH в переменную $_ заносится пойманный нами объект исключения. Потом мы берем его type object'а и приводим его к строке (.gist функция для дебага, позволяющая посмотреть внутренности объекта, описывать её здесь не буду).
Таким образом мы теперь получаем такой вывод:
Something is wrong! (X::Str::Numeric)
Another test work

Теперь мы знаем какое именно исключение словили. Копируем его имя и идем смотреть в Синопсах описание нашего исключения. (Вот прямая ссылка на наше исключение). После чего мы можем добавить ещё один блок when:
sub Func($a)
{
   my $temp = $a*2;
   say "Test work";

   CATCH
   {
      when X::Syntax::Name::Null
      {
          say "I will never say it =(";
      }
      when X::Str::Numeric
      {
          say "String convertation error!";
      }
      default
      {
          say "Something is wrong! "~$_.WHAT.gist;
      }
   }
}

Func "Test";
say "Another test work";


В результате чего увидем вывод:
String convertation error!
Another test work


Естественно мы можем через переменную $_ обращаться ко всем полям объекта. Поля опять же смотрим в описании исключения.

-Уфф, что-то я устал охотиться, может ловушек поставим, да передохнём?


Есть так же специальный блок try {}, внутри которого есть «невидимый» блок CATCH, и если внутри этого блока произойдет исключение, то работа скрипта не остановится, и выполнение продолжится со следующей инструкции после этого самого блока. Таким образом можно просто игнорировать все исключения которые нам попадутся.

Однако вам никто не запрещает внутрь этого блока добавить свой CATCH, который просто перезапишет уже существующий в нем. Смысл в использовании собственного CATCH блока внутри try — просто визуально показать что внутри этого блока может произойти исключение. Других побочных эффектов не наблюдается.

-А если попытается сбежать?


Вполне возможен вариант, что во время обработки одного исключения мы можем получить ещё одно. Однако стоит отметить, что блок when или default, в котором происходит обработка являются самыми обычными блоками, внутрь которых опять же можно поместить блок CATCH:
sub Func($a)
{
   try
   {
      my $temp = $a*2;
      say "Test work";

      CATCH
      {
         when X::Str::Numeric
         {
             die "test";
             CATCH
             {
                default
                {
                   say "Another die action";
                }
             }
         }
         default
         {
             say "Something is wrong! "~$_.WHAT.gist;
         }
      }
   }
}

Func "Test";
say "Another test work";


-А давай попытаемся приручить парочку исключений?


Пожалуй у нас найдется парачка способов, как можно самостоятельно создать исключение:

Первый способ это как вы уже заметили оператор 'die':
{
   die "I'm diying...";
   CATCH
   {
      default
      {
         say "I will save you!";
      }
   }
}


Второй способ — это вызов метода throw:
{
   X::Str::Numeric.throw;
   CATCH
   {
      default
      {
         say "More exception!?!";
      }
   }
}


Стоит также отметить, что возможно наследование своего класса от класса исключения, в результате чего мы можем создавать свои собственные исключения, но пока что по этому поводу обойдемся без примеров.

На этом я бы хотел закончить свой маленький гайд по выживании в жестоком мире исключений. Надеюсь вам быо интересно.
Tags:
Hubs:
+11
Comments 0
Comments Leave a comment

Articles