Работа с типами

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

Базовые типы

Наиболее простой путь ограничить допустимые передаваемые значения аргументов - указать имя типа перед параметром. Например, подпрограмма, производящая математические операции над своими параметрами, ожидает аргументы с типом Numeric:

    sub mean(Numeric $a, Numeric $b) {
        return ($a + $b) / 2;
    }

    say mean 2.5, 1.5;
    say mean 'some', 'strings';

Результат работы будет следующим:

    2
    Nominal type check failed for parameter '$a';
        expected Numeric but got Str instead

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

Добавление ограничений

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

    sub circle-radius-from-area(Numeric $area where { $area >= 0 }) {
        ($area / pi).sqrt
    }

    say circle-radius-from-area(3);    # OK
    say circle-radius-from-area(-3);   # Error

Так как расчет имеет смысл только для неотрицательных чисел, дополнительное ограничение возвращает True при соответствии входных значений этому диапазону. Если ограничение возвращает значение "Ложь", проверка завершается ошибкой.

Блок после where необязательный. Perl выполняет проверку посредством "умного" сопоставления, используя в качестве аргументов все, что находится после where. Таким образом возможно явное указание диапазона:

    sub set-volume(Numeric $volume where 0..11) {
        say "Turning it up to $volume";
    }

Для ограничения аргументов существующими ключами хэша:

    my %in-stock = 'Staropramen' => 8, 'Mori' => 5, 'La Trappe' => 9;

    sub order-beer(Str $name where %in-stock) {
        say "Here's your $name";
        %in-stock{$name}--;
        if %in-stock{$name} == 0 {
            say "OH NO! That was the last $name, folks! :'(";
            %in-stock.delete($name);
        }
    }