До сих пор в статьях было лишь поверхностное упоминание о типах данных — объявление переменной определенного типа, либо указание результата операции, но все что мы могли, это лишь терпеть выходки компилятора — «хочу умру (die), захочу варнинг кину, или просто поменяю тип».
Собственно, для тех кто хочет почувствовать себя богом хоть как-то важным в управлении типами в своем же скрипте, добро пожаловать под кат.
Итак, допустим мы написали функцию, которая принимает в качестве параметров две переменные:
sub Func($a, $b) {...}
И нужно нам, чтобы функция отрабатывала всегда одним образом, но если вдруг будут переданы в качестве параметров дробное число и строка, или же наоборот, то выполнить другие действия.
Начнем с малого — узнаем какой у нас тип данных у каждой из переменной, для этого используем метод WHAT, который вернет type object — объект обозначающий тип данных (например для значения 10 будет возвращен объект "(Int)" ). Следует отметить, что возвращается именно объект, а не строка, и простое сравнение двух типов через, например, == или eq не подойдет. Для того чтобы сравнить полученный объект с типом мы воспользуемся оператором умного сравнения '~~':
sub Func($a, $b)
{
$condition = ( ($a.WHAT ~~ (Rat)) ?& ($b.WHAT ~~ (Str)) );
$condition ?|= ( ($a.WHAT ~~ (Str)) ?& ($b.WHAT ~~ (Rat)) );
if ($condition)
{
#`(SomeWork)
}
else
{
#`{AnotherWork}
}
}
(Rat) и (Str) являются type object'ами действительных чисел и строк соответственно.
Для тех кто уже подзабыл ?& — Логическое «И», ?| — Логическое «ИЛИ».
И так, мы научились определять тип значения переменной, и взависимости от него выполнять какие либо действия. Но давайте посмотрим, в каких именно случаях это делать необходимо:
my Int $a;
sub Func($p)
{
$a = $p;
}
Func(10);
Func("Test");
В нашем случае, скрипт умирает когда пытается переменной, которая может содержать только целые числа, присвоить строку.
Подкорректируем немного наш пример, и напишем следующее:
$a = +($p);
В результате мы так же словим ошибку, и скрипт умрет, а ошибка будет не про присваивание а про неправильный тип в числовом контексте, из чего мы сделаем вывод, что частные контексты лишь добавляют ограничений по типам, и что для ручного преобразованя типов нам нужно что-то другое.
Попытаемся использовать следующую конструкцию:
$a = Int($p);
Уже лучше, так как если мы передадим число типа (Rat), то оно будет преобразовано к типу (Int), но вот если мы передадим строку, то получим уже ошибку преобразования строки в число, а именно о том, что строка должна иметь вид числа в 10-ой системе счисления.
Пока что я нашел только один способ заставить скрипт работать дальше — отлов исключений. На мой взгляд это самое логичное действие, но об этом мы поговорим в следующих статьях
Также наш скрипт может умереть если функция попытается вернуть значение, несоответствующее описанию:
sub Func($p) of Int
{
return $p;
}
Func("test");
Так что в данном случае, тоже не помешало бы сделать проверку выходных значений.
На последок хочу сказать, что по моему мнению ограничения на типы хранимых данных может сильно помочь в описании «интерфейсов» функций, и дают некоторые плюсы типизированных языков программирования.
Надеюсь эта информация была полезной.
Автор: WarFair