Интерполяция массивов и хэшей

Иногда требуется заполнить позиционные аргументы значениями из массива. Вместо написания eat(@food[0], @food[1], @food[2], ...) и так далее, вы можете линеаризовать (flatten) его в список аргументов предварив вертикальной чертой: eat(|@food).

Кроме того, можно интерполировать хэши в именованные аргументы:

    sub order-shrimps($count, $from) {
        say "I'd like $count pieces of shrimp from the $from, please";
    }

    my %user-preferences = ( from => 'Northern Sea' );
    order-shrimps(3, |%user-preferences)

Необязатльные параметры

Иногда аргументы могут быть необязательными. Например, достаточно других параметров с их значениями по умолчанию. В таких случаях подобные необязательные параметры можно пометить как опциональные. При вызовах таких подпрограмм появляется выбор в наборе передаваемых аргументов.

Либо присвоить значение параметра по умолчанию в сигнатуре :

    sub order-steak($how = 'medium') {
        say "I'd like a steak, $how";
    }

    order-steak();
    order-steak('well done');

... или добавить знак вопроса к имени параметра. В последнем случае параметр получает неопределенное значение, если аргумент не передан:

    sub order-burger($type, $side?) {
       say "I'd like a $type burger" ~
           ( defined($side) ?? " with a side of $side" !! "" );
    }

    order-burger("triple bacon", "deep fried onion rings");

Именованные параметры

Когда подпрограмма имеет много параметров, зачастую, проще привязывать параметры к имени вместо к их позиции в списке передаваемых аргументов. Как следствие, порядок следования аргументов при вызове становиться неважным:

    sub order-beer($type, $pints) {
        say ($pints == 1 ?? 'A pint' !! "$pints pints") ~ " of $type, please."
    }

    order-beer(type => 'Hobgoblin', pints => 1);
    # A pint of Hobgoblin, please.

    order-beer(pints => 3, type => 'ZlatГ?? BaЕ??ant');
    # 3 pints of ZlatГ?? BaЕ??ant, please.

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

    sub order-shrimps($count, :$from = 'North Sea') {
        say "I'd like $count pieces of shrimp from the $from, please";
    }

    order-shrimps(6);                       # takes 'North Sea'
    order-shrimps(4, from => 'Atlantic Ocean');
    order-shrimps(22, 'Mediterranean Sea'); # not allowed, :$from is named only

В отличии от позиционных параметров, именованные являются необязательными по умолчанию. Чтобы сделать именованный параметр обязательным необходимо добавить к имени параметра восклицательный знак !.

    sub design-ice-cream-mixture($base = 'Vanilla', :$name!) {
        say "Creating a new recipe named $name!"
    }

    design-ice-cream-mixture(name => 'Plain');
    design-ice-cream-mixture(base => 'Strawberry chip'); # missing $name

Переименование параметров

Так как требуется указывать имена при передаче именованных параметров, то данные имена являются частью общедоступного API подпрограмм. Выбирайте имена осторожно ! Иногда может оказаться полезным отделить имя параметра от имени переменной подпрограммы, с которой он связан:

    sub announce-time(:dinner($supper) = '8pm') {
        say "We eat dinner at $supper";
    }

    announce-time(dinner => '9pm');      # We eat dinner at 9pm

Параметры могут иметь несколько имен ! Если часть пользователей британцы, а остальные - американцы, то можно написать:

    sub paint-rectangle(
            :$x      =   0,
            :$y      =   0,
            :$width  = 100,
            :$height =  50,
            :color(:colour($c))) {

       # print a piece of SVG that reprents a rectangle
       say qq[<rect x="$x" y="$y" width="$width" height="$height"
                     style="fill: $c" />]
    }

    # both calls work the same
    paint-rectangle :color<Blue>;
    paint-rectangle :colour<Blue>;

    # of course you can still fill the other options
    paint-rectangle :width(30), :height(10), :colour<Blue>;

Альтернативный синтаксис Именованных параметров

Именованные параметры на самом деле являются Парами ( Pair, пара ключ - значение). Существует несколько способов описания Пар. Отличаются они степенью наглядности, так как каждый вариант предусматривает различные механизмы оформления. Следующие три вызова эквивалентны:

    announce-time(dinner => '9pm');
    announce-time(:dinner('9pm'));
    announce-time(:dinner<9pm>);

Если передается логическое значение, то достаточно определения ключа:

    toggle-blender( :enabled); # enables  the blender
    toggle-blender(:!enabled); # disables the blender

Именованный параметр :name без указанного значения подразумевает неявное логическое значение Bool::True. Противоположная форма, :!name, указывает на неявное значение Bool::False.

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

    my $dinner = '9pm';
    announce-dinner :$dinner;  # same as dinner => $dinner;

В следующей таблице приведены возможные формы Пар и их значения.

Таблица 4.1. Формы Пар и их значения

Краткая формаПолная формаОписание
:allowedallowed => Bool::TrueЛогичекий флаг
:!allowedallowed => Bool::FalseЛогичекий флаг
:bev<tea coffee>bev => ('tea', 'coffee')Список
:times[1, 3]times => [1, 3]Массив
:opts{ a => 2 }opts => { a => 2 }Хэш
:$varvar => $varСкалярная переменная
:@varvar => @varПеременная - массив
:%varvar => %varПеременная - хэш

Возможно использование любой из указанных форм в любом контексте, где возможно использование объекта Pair.Например, для заполнения массива:

    # TODO: better example
    my $black = 12;
    my %color-popularities = :$black, :blue(8),
                             red => 18, :white<0>;
    # same as
    # my %color-popularities = 
    #       black => 12,
    #       blue  => 8,
    #       red   => 18,
    #       white => 0;

И наконец, чтобы передать существующий объект Pair в подпрограмму как позиционный параметр (не именнованный), необходимо либо заключить его в круглые скобки ( (:$thing) ), либо использовать оператор => с взятой в кавычки левой частью: "thing" => $thing.

Последовательность параметров

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

    sub mix(@ingredients, :$name) { ... }    # OK
    sub notmix(:$name, @ingredients) { ... } # Error

Обязательные позиционные параметры также должны быть указаны перед опциональными (необязательными) позиционными. Для именованных параметров нет подобных требований.

Slurpy параметры

В приведенном ранее примере функция shout-it ожидала массив в качестве аргумента. Это предотвращало передачу одиночного аргумента. Что бы сделать возможным передачу нескольких позиционных аргументов и даже массивов аргументов, которые будут затем в подпрограмме выравнены (flatten) в один аргумент "массив", необходимо предварить имя параметра slurpy префиксом (*):

    sub shout-them(*@words) {
        for @words -> $w {
            print uc("$w ");
        }
    }

    # now you can pass items
    shout-them('go');           # GO
    shout-them('go', 'home');   # GO HOME

    my @words = ('go', 'home');
    shout-them(@words);         # still works

Slurpy параметр ( параметр с прешествующeй его имени звездочкой * ) сохраняет ожидаемые позиционные параметры в массив. Кроме того, *%hash захватывает [2] все входящие несвязанные именованные аргументы в хэш.

Slurpy массивы и хши позволяют передавать все позиционные и именованные параметры в другом порядке:

    sub debug-wrapper(&code, *@positional, *%named) {
        warn "Calling '&code.name()' with arguments "
             ~ "@positional.perl(), %named.perl()\n";
        code(|@positional, |%named);
        warn "... back from '&code.name()'\n";
    }

    debug-wrapper(&order-shrimps, 4, from => 'Atlantic Ocean');



[2] slurp, переводиться как - хлебать