Захватывания

В каком-то смысле, сигнатура представляет собой "коллекцию" аргументов. Захватывания (captures) представляют собой сущности того же уровня. Так же, как вы редко думаете о сигнатуре в целом, сосредотачиваясь на каждом отдельно взятом параметре, так же редко вы должны редко думать о "захватываниях". Однако, Perl 6 позволяет управлять захватываниями напрямую. Захватывания состоят из позиционных и именованных частей, которые действуют аналогично спискам и хэшам соответственно. Списочная часть содержит позиционные аргументы, а хэш составляющая - именованные аргументы.

создание и использование захватываний

Чтобы создать захватывание, используется \(...) синтаксис. Подобно массивам и хэшам, можно интерполировать захватывание в один аргумент с помощью |:

    sub act($left, $right, :$action) {
        $action($left, $right);
    }

    my @tasks = \(39, 3, action => { say $^a + $^b }),
                \(6, 7, action => { say $^a * $^b });

    for @tasks -> $task-args {
        act(|$task-args);
    }

Эта программа создает массив "захватываний", каждое из которых содержит два позиционных аргумента и один именованный. При выполнении цикла по элементам массива выполняется вызов act, аргументы которого заполняются содержимым захватывания. Perl 6 позволяет отдельно определить аргументы для вызова и сам вызов. Как следствие, это позволяет использовать одни и те же аргументы для многократных вызовов, а также использовать вызов для разных наборов аргументов. Коду приложения не обязательно знать является ли аргумент позиционным или именованным. В отличии от сигнатур, захватывания работают аналогично ссылкам. Любая переменная, указанная в "захватывании", представлена как ссылка на переменную.Таким образом rw параметры продолжают работать при использовании "захватываний".

    my $value     = 7;
    my $to-change = \($value);

    sub double($x is rw) {
        $x *= 2;
    }

    sub triple($x is rw) {
        $x *= 3;
    }

    triple(|$to-change);
    double(|$to-change);

    say $value; # 42

Типы Perl с позиционными и именованными частями встречаются также в других ситуациях. Например, регулярные выражения имеют позиционные и именованные выражения: объекты типа Match представляют собой "захватывания". Также возможно представить XML узлы одним из видов "захватываний", включающих в себя именованные атрибуты и позиционные потомки. Привязка такого узла к функции позволяет использовать единый синтаксис параметров для работы с различными потомками атрибутами.

Захватывания в Сигнатурах

Все вызовы создают захватывания на этапе вызова и разворачивают их в соответствии с сигнатурой внутри вызова [3]. Это позволяет написать сигнатуру, которая свяжет само "захватывание" с переменной. Это особенно полезно при написании процедур, которые делегируют управление другим процедурам с теми же параметрами.

    sub visit-czechoslovakia(|$plan) {
        warn "Sorry, this country has been deprecated.";
        visit-slovakia(|$plan);
        visit-czech-republic(|$plan);
    }

Преимущества такого использования в сравнении с сигнатурой вида :(*@pos, *%named) заключаются в отсутствии некоторого контекста в аргументах, который может быть преждевременным. Например, если при вызове передаются два массива, они будут линеаризованы в @pos. Это значит, что в дальнейшем эти два массива не могут быть восстановлены в оригинальном виде. "Захватывание" сохраняет аргументы из двух массивов, что поможет при связывании их в сигнатурах вызываемых в итоге подпрограмм.



[3] Оптимизатор Perl 6 может, конечно, допускать оптимизации на любом из этих этапов, в зависимости от информации, которая может быть доступна на этапе компиляции.