Некоторые сведения о Perl 5/Типы данных

Глава Операции и выражения →
Типы данных


В языке Perl всего три основных типа данных:

  • Скаляр. Предназначен для представления и обработки чисел и последовательностей символов (строк).
  • Массив скаляров. Предназначен для хранения и обработки нескольких скалярных данных, доступ к которым осуществляется по индексам.
  • Ассоциативный массив скаляров (иногда называемый хешем). Предназначен для создания различных динамических структур: списки, деревья и прочее.

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

Скаляры править

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

25        # Целое число
64.567    # Вещественное число
0.546     # Вещественное число с нулевой целой частью
.546      # Несущественные нули допустимо опускать

# В языке Perl для больших чисел разряды можно отделять друг от друга символом нижнего подчеркивания
# для улучшения читаемости кода.
5465249.682   # Так, следующий числовой литерал может быть записан
5_465_249.682

# Восьмеричные и шестнадцатеричные числа
021  # в десятеричной системе 17. Ведущий ноль указывает на восьмеричную систему счисления

# Шестнадцатеричные числа всегда начинаются на префикс "0x", причем использовать "0X" НЕЛЬЗЯ.
# Буквы A-F могут быть записаны в любом регистре.
0xAB3
0xf

Вещественные числа с плавающей точкой могут быть записаны в экспоненциальной форме:

#  [цифры].[цифры][E|e][+|-][цифры]
#    <мантисса>   E  <экспонента>

12.567E12
12.567E+04
1e-85
1E+12

Хотя внешне кажется, что целые и вещественные числа это что-то разное, внутри Perl все числа представляются в формате чисел с плавающей точкой удвоенной точности. Это означает, что экспонента должна быть в пределах -323 до +308, а мантисса может иметь не более 16 значащих цифр. При выходе за этот диапазон скаляру будет присвоено 0 в меньшем пределе и специальный символ 1.#INF — в большем пределе, означающем бесконечно большое число.

Строковые литералы должны всегда ограничиваться одинарными ('), двойными (") или обратными (`) кавычками. В строковых литералах, ограниченных одинарными кавычками, нельзя использовать управляющие последовательности или экранирование, кроме двух: \' (отображает одинарную кавычку) и \\ (отображает обратный слеш). Другими словами, одинарные кавычки используются, когда все символы в литерале нужно понимать буквально. Двойные кавычки используются, когда управляющие последовательности должны быть переданы устройству вывода, например для переноса строки или табуляции.

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

'Very long string\n'       # Строковый литерал. В нем управляющая последовательность '\n' не будет интерпретироваться
"\tVery long string\n"     # Две управляющие последовательности будут переданы на устройство вывода, т.е. текст выведется
                           # с отступом и в конце будет перенос на новую строку

'Каталога \'~john/docs\' не существует'   # Мы используем одинарные кавычки в литерале, чтобы подчеркнуть путь.
'Диск E:\\ переполнен'                    # Будет выведено "Диск E:\ переполнен".

`ls`   # Литералом будет вывод команды ls.

Разобравшись в том, что можно хранить в скаляре, рассмотрим как он объявляется. Скаляр, как впрочем и любой другой тип, должен быть присвоен переменной, которая будет отсылать нас на некоторый участок памяти. Присваивание скаляра переменной будет в итоге определять ее тип, как переменная, хранящая скаляр. Для обозначения такой переменной в Perl используется символ доллара $:

$scalar_variable;
$deviceName;
$name_1;

# Здесь $ означает, что переменная хранит скаляр, а идентификатор за ним означает имя переменной.
# В общем случае скаляр может не иметь значения.

Скалярная переменная за один раз может хранить либо число, либо строку, причем не существует способа заранее определить что из этого хранится в скаляре. Это связано с тем, что в Perl существует механизм неявного преобразования, который включается когда со скалярами производятся операции. Например, при арифметической операции над двумя скалярами, Perl сначала попытается преобразовать их в числа. Напротив, при строковой конкатенации оба скаляра должны быть преобразованы в строки. Если Perl по какой-то причине не удается преобразовать значение в контексте операции, то интерпретатором будет генерироваться ошибка.

$price = 15;                       # Скаляр хранит число
print "Книга стоит $price рублей";  # В контексте данной операции число будет преобразовано в строку

# Если при подстановке скаляра за именем переменной идут символы, которые можно использовать в именах переменных
# (то есть если за подстановкой нет разделителя), нужно поместить имя переменной в фигурные скобки.
$day = 15;
print "January ${day}th"; # January 15th

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

$day = Friday;   # Допустимо

# Однако, без кавычек можно оставлять строковые литералы, которые имеют только буквы латинского алфавита.

Массивы скаляров править

Массив скаляров позволяет представить не один скаляр, а сразу несколько, доступ к которым осуществляется по индексам. Для объявления массива используется пара круглых скобок, называемая конструктором массива. Так как скаляр может хранить числа или строки, то с точки зрения Perl массив может хранить смешанные данные.

$day = 15;
("скаляр_1", 156, "скаляр_3", $day)  ;

При присваивании массива переменной, перед ее именем используется символ @, который указывает, что переменная хранит массив скаляров. Чтобы обратиться к скаляру в массиве, используется синтаксис, подобный обращению к скаляру, но за именем переменной в квадратных скобках указывается индекс. Тем самым, язык подчеркивает, что массив хранит скаляры. Элементы в массиве скаляров отсчитываются с нуля.

@array = ("one", 2, "three", 4);

print "Element 0: $array[0]\n";       # Печатаем элемент с индексом 0
print "Element 1: ${array[1]}d\n";    # Печатаем элемент с индексом 1

# Допускается использование отрицательных индексов: в этом случае -1 означает последний элемент,
# -2 – предпоследний и т.д.
print "Element 2: $array[-2]\n";
print "Element 3: $array[-1]\n";

$array[3] = 5;   # Изменяем значение с индексом 3

print "Element 3: $array[3]\n";

# Чтобы узнать последний индекс массива, используется такой синтаксис, где
# за символом решетки идет имя массива. Такой прием используется для вычисления его размера.
print "Last index: $#array\n";

$arr2[0] = 51;  # Массив также порождается при добавлении в него хотя бы одного значения

print $arr2[0];

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

Как и скаляры, массивы можно распечатать с помощью print.

@digits = (1..9);  # В данном примере мы сформировали массив через диапазон

print "Digits: @digits\n";    # Когда массив подставляется в другой строковый литерал, его элементы будут перечислены через пробел.
print "@digits\n";            # Или так.
print @digits, "\n";          # Но если оператору он будет передан так, то вывод будет без отделения пробелом.

Результат вывода

Digits: 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
123456789

Печать элементов массива аналогична печати скаляров, однако здесь следует упомянуть интересную особенность:

$digit = 6;
@digit = (5);
# В Perl такая ситуация не запрещена.

# Что будет здесь напечатано?
print "$digit[0]\n"
# Правильный ответ будет 5, но в таком случае как нам напечатать скаляр $digit при такой конфигурации строки.
# Здесь существует несколько подходов и все они направлены на то, чтобы синтаксис с индексом
# представить как строковый литерал.

# Следующие три вызова напечатают "6[0]".
print "${digit}[0]\n";
print "$digit\[0]\n";
print "$digit" . "[0]\n";  # Оператор . конкатенирует строки

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

@digits = (1..15);

print "@digits[5,10,14]\n";   # В квадратных скобках через запятую перечисляются индексы элементов, которые мы хотим увидеть в срезе
print "@digits[5..10]\n";     # Диапазон индексов
print "@digits[1,2,5..9,12,13]\n";  # Смешанный подход

Результат

6 11 15
6 7 8 9 10 11
2 3 6 7 8 9 10 13 14

Ассоциативные массивы скаляров править

Ассоциативные массивы используются в Perl для создания сложных структур, когда возможностей простых массивов не хватает. Концептуально ассоциативные массивы отличаются от простых массивов тем, что в них для ссылки на элементы используются ассоциативные ключи. Ассоциативный ключ является строковым литералом. Далее для краткости мы будем говорить хеш-массив, однако имейте в виду, что оба слова равнозначны.

Хеш-массив можно объявить по-разному:

# Хеш-массив создается как простой массив, но теперь необходимо в нечетные элементы
# помещать ассоциативные ключи, которые будут связываться со значениями, идущими за ними.
(key1, value1, key2, value2)   ;

# Чтобы подчеркнуть то, что в переменной хранится хеш-массив, используется символ '%'.
%person = (name, "Larry", surname, "Wall");

# Здесь 'name' ассоциативный ключ к скаляру "Larry", а 'surname' — к "Wall".
# Чтобы обратиться к элементу хеш-массива по ключу, используется синтаксис $имя-хеш-массива{"ключ"}.
print "Name: $person{name}\nSurname: $person{surname}\n";

# Создание массива через такой конструктор удобен, когда вы преобразуете обычный массив в хеш-массив.
# В большинстве случаев следующий способ объявления хеш-массива удобнее.
%person = (
    name => "Larry",
    surname => "Wall"
);

print "Name: $person{name}\nSurname: $person{surname}\n";

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

%person = (
    name => "Larry",
    surname => "Wall",   # запятая здесь не ошибка
);

Для добавления нового элемента в хеш-массив или изменения существующего, достаточно просто обратиться по ключу. Если элемента не было, то он будет создан.

%person = (
    name => "Larry",
    surname => "Wall"
);

print %person, "\n";

$person{name} = "Garry";    # Значение по существующему ключу будет изменено
$person{phone} = 1234;      # Новое значение будет добавлено

print %person, "\n";

delete($person{name});      # Удалить существующий элемент можно с помощью функции delete

print %person, "\n";

Для хеш-массивов существуют две встроенные функции, которые позволяют распечатать либо все ключи, либо все значения в массиве.

%person = (
    name => "Larry",
    surname => "Wall",
    phone => 1234,
);

print keys(%person), "\n";     # Печатает все ключи хеш-массива
print values(%person), "\n";   # Печатает все значения хеш-массива

О переменных править

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

  • Переменная в Perl, как и в любом языке программирования, это именованный участок памяти. Первый символ перед именем переменной определяет ее тип: $ (скаляр), @ (массив скаляров), % (хеш-массив).
  • Имя переменной чувствительно к регистру и может состоять из цифр, букв и символа нижнего подчеркивания и не должно начинаться с цифры, а также не должно совпадать с зарезервированным в Perl словом. В Perl может быть создано три одноименных переменных, каждая из которых хранит по отдельному типу данных, например $var, @var и %var. Это возможно потому, что интерпретатор хранит имена переменных в разных списках для разных типов.
  • В выражениях, когда в качестве операнда используется некоторый тип, его интерпретация может зависеть от контекста, в котором он вычисляется, в частности существует два контекста: скалярный и списковый (векторный). Это важно, так как от этого будет зависеть конечный результат выражения. Об этом будет подробно рассказано, когда речь пойдет об операциях.
  • Любая переменная может находиться в состоянии определена или не определена. Переменная считается определенной, если ей присвоено какое-то значение. Чтобы определить статус переменной, следует пользоваться встроенной функцией defined.
  • Переменную можно сделать неопределенной, если вызвать функцию undef. Вызов этой функции будет приводить к освобождению памяти от ненужных данных.
  • Любая переменная имеет некоторую видимость относительно других участков программы. Видимость зависит от того, где и как переменная объявлена. Например, в вышеприведенных примерах все переменные были объявлены в глобальной области видимости. Когда переменная выходит из своей области видимости, она уничтожается.



Операции и выражения →