Perl6 — Ещё немного о блоках (Phasers)

от автора

1. Особенности работы с переменными и литералами в Perl6
2. Perl6 — Операции над переменными, анонимные блоки
3. Perl6 — Условные операторы, циклы
4. Perl6 — Работа с функциями
5. Perl6 — Классы
6. Perl6 — Ввод-вывод, модули
7. Perl6 — Комментарии, пробельные символы, скобки
8. Perl6 — Перегрузка операторов
9. Perl6 — Работа с типами данных
10. Perl6 — Обработка исключений
В прошлой статье мы говорили об отлове исключений, что происходило в специальном вложенном блоке CATCH. На самом деле этот блок является особой разновидностью — Phasers (я просто не могу перевести это слово). Phasers — это специальные вложенные блоки, которые выполняются при определенных условиях. С чем же их готовить увидите под катом.

Рассмотрим основных представителей Phaser’ов:

  • BEGIN {…}*
    Данный блок выполняется единожды при компиляции приложения, причем последний вычисленный результат (как и в дальнейшем у блоков отмеченных звездочкой) может быть использован как результат для присвоения переменной:
    say "Test say";  my $block = BEGIN {   say "Compile say";   "Compile time " ~ now; }  say $block; 

    В данном случае переменной блок будет присваиваться строка отражающая время компиляции (Причем как я понял сам блок выполняется при компиляции, а при выполнении скрипта переменной присваивается уже вычисленного значения).
    В результате мы увидим на экране:

    Compile say Test say Compile time Instant:1377026323.088 

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

    say "Test say";  my $block = BEGIN {   die "Compile die";   "Compile time " ~ now; }  say $block; 

    То на экране мы уже не увидим надписи «Test say», а сразу «Compile die», хотя вывод и происходит раньше чем присвоение результата выполнения блока BEGIN.
    Ну и последний пример по этому блоку, чтобы развеять возможные сомнения:

    say "Test say";  BEGIN {   say "Compile say"; }  say "Test say 2";  BEGIN {   say "Compile say 2"; } 

    В результате мы увидим на экране:

    Compile say Compile say 2 Test say Test say 2 

  • CHECK {…}*
    Аналогично предыдущему, но действия выполняются после выполнения компиляции но до выполнения самого скрипта, однако как я заметил в обратном порядке следования в коде:
    say "Test say";  BEGIN {   say "Compile say"; }  CHECK {   say "Check say"; }  say "Test say 2";  BEGIN {   say "Compile say 2"; }  CHECK {   say "Check say 2"; } 

    В результате мы увидим на экране:

    Compile say Compile say 2 Check say 2 Check say Test say Test say 2 

  • INIT {…}*
    Данный блок выполняется при запуске скрипта:
    say "Test say";  BEGIN {   say "Compile say"; }  CHECK {   say "Check say"; }  INIT {   say "Init say"; }  say "Test say 2";  BEGIN {   say "Compile say 2"; }  CHECK {   say "Check say 2"; }  INIT {   say "Init say 2"; } 

    В результате вывод следующий:

    Compile say Compile say 2 Check say 2 Check say Init say Init say 2 Test say Test say 2 

  • END {…}
    Блок выполняется при остановке скрипта. Стоит отметить, что выполняется он так же как и в случае с CHECK в обратном порядке как были встречены в скрипте, и ещё одну важную вещь — данный блок выполняется даже если в скрипте произошло исключение:
    say "Test say";  BEGIN {   say "Compile say"; }  CHECK {   say "Check say"; }  INIT {   say "Init say"; }  END {   say "End say"; }  say "Test say 2";  BEGIN {   say "Compile say 2"; }  CHECK {   say "Check say 2"; }  INIT {   say "Init say 2"; }  END {   say "End say 2"; }  die "test die"; 

    В результате видим на экране:

    Compile say Compile say 2 Check say 2 Check say Init say Init say 2 Test say Test say 2 test die   in block  at bla\bla\bla\perl.p6:37  End say 2 End say 

  • ENTER {…}*
    Данный блок выполняется при любом выполнении блока, в который вложен блок ENTER:
    loop (my $i=0; $i <4; $i++) {    ENTER {       say $i;    }    say "Another loop entry"; }  ENTER {    say "Test Enter"; } 

    Вывод данного скрипта:

    Test Enter 0 Another loop entry 1 Another loop entry 2 Another loop entry 3 Another loop entry 

    Стоит также отметить то, что можно блоки Phasers вкладывать друг в друга.

  • LEAVE {…}
    Выполняется при завершении работы блока, в который LEAVE был вложен. Вот тут вот я и сново столкнулся с проблемами, из-за которых я и отложил в прошлый раз изучение — я опять начал получать невнятные ошибки если поставил не туда пробел. А пример с блоком LEAVE у меня просто напросто не скомпилировался, оповещая меня о ошибке с неправильным количеством параметров у оператора return, который я кстате и не пытался использовать. Но пример я всетаки приведу:
    loop (my $i=0; $i <4; $i++) {    LEAVE {       say "Test leave";    }    say "Another loop entry"; } 

    Если вдруг кто-нибудь сможет это скомпилировать, поведайте пожалуйста в комментариях.
    Как в дальнейшем я выяснил, не работает часть, связанная с выходом из блока. Но перейдем дальше:

  • KEEP {…}
    Данный блок выполняется при успешном выполнении всего блока (как именно определяется успешность проверить не смог, так как скрипт с использованием такого блока не компилируется).
  • UNDO {…}
    Аналогично предыдущему блоку, но в случае если выполнение было завершено не успешно. Пример тоже не компилируем.
  • FIRST {…}*
    Данный блок выполняется только при первом запуске блока, в который вложен FIRST:
    loop (my $i=0; $i <4; $i++) {    FIRST {say "Test keep";}    say "Another loop entry"; } 

    Соответственно вывод:

    Test keep Another loop entry Another loop entry Another loop entry Another loop entry 

Так же в отдельный список выведены операторы, которые действуют подобно Phaser’ам, которые пишутся в нижнем регистре:

  • do {…}*
    Выполняет все операции в блоке, а результат представляет в виде терма. Пример использования:
    if ( do {my $a = 10; $a = $a*2;} == 20) {    say "It's ok"; } 

    Таким образом мы вложили вычисление внутрь блока if, а сам блок do можно будет использовать потом для сравнения. Пример конечно очень плохой для ваших пальцев (можно и линейкой схлопотать по ним за такое), но для того чтобы показать для чего он может быть использован пример сгодится.

  • once {…}*
    Данный блок должен будет выполниться лишь раз. К сожалению проверить я так и не смог, так как пример не компилируем:
    my $i = once {    say "Test once"; };  $i(); $i(); $i(); 

    Жалуется на то, что не смог найти функцию &once.

  • try {…}*
    Знакомый по предыдущей статье блок, игнорирующий все исключения.
  • lazy {…}*
    По описанию должен возвращать «обещание» о выполнении. К сожалению результат для него как и у ‘once’ блока. Как я понял данный блок должен помочь нам в организации «ленивых вычислений».
  • async {…}
    Выполняет блок в новом потоке. К сожалению опять же не смог скомпилировать пример. Зато теперь имею представление о том как будет происходить работа с потоками.

Чтож, пожалуй пора заканчивать. Как-то даже длинновай пост получился из-за примеров, но надеюсь вам понравилось.

ссылка на оригинал статьи http://habrahabr.ru/post/190778/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *