Глава 6.2. Основные понятия

6.2.1. Типы данных и переменные

PERL имеет всего три встроенных типа данных: скаляры, массивы и ассоциативные массивы (hashes). Скаляры — это числа, строки и ссылки. Массивы — это упорядоченные списки значений, которые доступны по номеру в списке и нумеруются с нуля. Ассоциативные массивы — это неупорядоченные списки значений, которые индексируются строковыми ключами.

Идентификаторы используются в PERLе в качестве имен переменных, подпрограмм, меток и т. п. Они могут начинаться с латинской буквы или символа "_" (подчеркивание) и должны состоять из латинских букв, цифр и подчеркиваний. Перед именем переменной всегда ставится специальный символ, который указывает на ее тип:

Символ Тип данных
$ Скаляр
@ Массив
% Ассоциативный массив
& Подпрограмма (необязателен)
* Ссылка на таблицу символов

Приведем примеры образования имен переменных.

$day Простая скалярная переменная.
$days[5] 6-й элемент массива @days.
$days('May') Элемент ассоциативного массива %days, соответствующий ключу 'May'.

Каждый тип переменных имеет собственное пространство имен, поэтому мы можем использовать один и тот же идентификатор для скаляра, массива, ассоциативного массива и подпрограммы. Например, $name и @name — это разные переменные. Два идентификатора считаютс одинаковыми, когда они полностью совпадают; это означает, что name, Name и NAME являются различными идентификаторами.

Особую группу переменных образуют т. н. специальные переменные, в которых хранится разнообразная служебная информация. Специальные переменные описываются в тексте по мере надобности в них; их полный перечень приведен в Приложении 22.

6.2.2. Зарезервированные слова

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

6.2.3. Константы

Константы используются для задания постоянных значений. Ниже описаны правила формирования констант в зависимости от типа их значений.

6.2.3.1. Числовые константы

Числовые константы могут быть как целыми, так и плавающими. PERL не проводит между ними различия и, в действительности, хранит все числа как плавающие. Целые числа могут быть положительными, отрицательными и нулем. По системе счисления они могут быть десятичными, двоичными, восьмеричными и шестнадцатеричными:

  • Десятичные числа — это просто набор десятичных цифр, например: 1234, -256. Они могут содержать символ подчеркивания для удобства чтения: 1_234_567 эквивалентно 1234567.
  • Двоичные числа начинаются с 0b и состоят из цифр 0 и 1, например: 0b001001.
  • Восьмеричные числа начинаются с 0 и состоят из цифр 0 — 7, например: 01234, -067.
  • Шестнадцатеричные числа начинаются с 0x и состоят из цифр 0 — 9 и букв A — F в любом регистре, например: 0xA000, 0xa000, -0x1234.

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

0.0001, .0001, 1e-4, 1.0E-4 // Четыре плавающих числа, равных друг другу
-1.23e2 // Плавающее число, равное -123

6.2.3.2. Строковые константы

PERL содержит два формата строковых констант. Первый формат имеет вид строки, заключенной в апострофы, например, 'текст'. Такие строки воспринимаются интерпретатором буквально, без анализа их содержимого. Вместо апострофов можно использовать формат q/текст/, причем вместо дробной черты допустим любой символ-разделитель или парные разделители: (), [], {}, <>. Примеры:

print 'текст';
print q/текст/;
print q#текст#;
print q[текст];

Второй формат имеет вид строки, заключенной в кавычки, например, "текст". Такие строки анализируются интерпретатором, который заменяет в них имена переменных и escape-последовательности на соответствующие значения. Этот процесс называется интерполяцией. Вместо кавычек можно использовать формат qq/текст/, причем вместо дробной черты допустим любой символ-разделитель или парные разделители. Примеры:

print "текст\n";
print qq/текст\n/;
print qq*текст\n*;
print qq{текст\n};

Здесь \n задает символ перевода строки. Такие обозначения называются escape-последовательностями и имеют вид \xXX, где XX — шестнадцатеричный код символа, или \0XXX, где XXX — восьмеричный код символа Unicode. Для задания кодов Unicode, больших 256, используется формат \x{XXXX}. Кроме того, несколько символов могут обозначаться специальными escape-последовательностями:

\a \x07 звонок (BEL)
\b \x08 забой (BS)
\t \x09 табуляция (HT)
\n зависит от системы новая строка (NL)
\f \x0C перевод формата (FF)
\r \x0D возврат каретки (CR)
\e \x1B escape (ESC)
\" \x22 двойная кавычка (")
\' \x27 апостроф (')
\\ \x5C обратная косая черта (\)
\cсимвол код символа - 0x40 управляющий символ (например, \c[ эквивалентно \e)

Следующие escape-последовательности управляют преобразованием символов строки:

\l преобразовать следующий символ в строчную букву
\u преобразовать следующий символ в прописную букву
\L преобразовывать в строчные буквы до \E
\U преобразовывать в прописные буквы до \E
\Q выводить символ "\" перед символами, недопустимыми в идентификаторах, до \E
\E конец преобразований

Для того, чтобы преобразование символов правильно работало с русскими буквами, используйте директиву set locale, например:

use locale;
print "\Uабвгд\E\n";

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

$price = '100 руб.';
print "Цена: $price\n";
print 'Цена: $price\n';

Эта программа выведет на экран строки:

Цена: 100 руб.
Цена: $price\n

Еще один способ кодирования строк Unicode имеет вид: vXXX.YYY.ZZZ, где XXX, YYY и ZZZ — десятичные коды символов. Если такая конструкция содержит более одной точки, то символ v в начале можно опустить. Примеры:

print v169;         # выводит символ ©
print v102.111.111; # выводит строку "foo"
print 102.111.111;  # то же самое

Для выполнения внешних программ или команд операционной системы используются строковые константы вида `команда`. Вместо символа "`" можно использовать формат qx/команда/, причем вместо дробной черты допустим любой символ-разделитель или парные разделители. Такая строковая константа возвращает в качестве результата все, что указанная команда выводит на стандартное устройство вывода системы (stdout). Например, оператор print `set`; выведет на экран текущее состояние системного окружения. Затем полученная строка анализируется интерпретатором так же, как если бы она была заключена в кавычки, если только строка не имела вида qx'команда'.

6.2.3.3. Специальные константы

PERL поддерживает пять специальных констант:

__FILE__ имя текущего файла
__LINE__ номер текущей строки файла
__PACKAGE__ имя текущего пакета
__END__ логический конец программы
__DATA__ начало данных программы

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

print "Ошибка в ".__FILE__.", строка ".__LINE__."\n";

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

Константы __END__ и __DATA__ обозначают логический конец программы: все, что следует за ними в файле программы, будет проигнорировано. Различие между ними состоит в том, что текст после __DATA__ доступен для чтения из файла с именем packname::DATA, где packname — имя текущего пакета (см. п. 6.7.1).

6.2.4. Преобразования скалярных типов

Как указывалось выше, числа и строки не являются в PERLе отдельными типами, а относятся к единому скалярному типу. Это, в частности, означает, что значения скалярных переменных по мере необходимости автоматически преобразуются в строку или число. Рассмотрим пример:

$x = 2;
$y = 4;
$z = ($x.$y) / 2;
print $z;

Здесь оператор присваивания выполняет три неявных преобразования типа. Поскольку операция "." означает в PERLе конкатенацию строк, переменные $x и $y будут преобразованы в строки "2" и "4", которые дадут строку "24". Далее в операторе стоит деление на 2, поэтому полученная строка будет преобразована в число и поделена пополам. В результате данный пример выведет на экран значение 12.

Автоматические преобразования обычно облегчают написание программ, но требуют от программиста внимания. Рассмотрим для примера сравнение строк. В зависимости от контекста PERL может сравнить их как строки или как числа, что приводит к разным результатам. Так, строки "1" и "01" различны, но при преобразовании в число становятся равными. По этой причине PERL содержит два набора операций сравнения: для чисел и для строк.

PERL не поддерживает логических значений, но содержит логические операторы и операции. В контексте этих операторов и операций действует следующее соглашение: неопределенное значение undef считается ложным; число считается ложным, если оно равно нулю; строка считается ложной, если она пуста или равна "0". Все остальные скалярные значения считаются истинными.

Скалярные переменные могут содержать, помимо чисел и строк, ссылки на другие переменные и объекты. Ссылки отличаются тем, что они являются строготипизированными указателями со встроенным счетчиком ссылок и деструктором объекта, вызываемым по обнулению этого счетчика. Важно помнить, что ссылочные переменные не подвержены автоматическому преобразованию типов.

6.2.5. Списки

Одним из важнейших механизмов PERLа являются списки. Список — это набор выражений, разделенных запятыми и обычно заключенный в круглые скобки. Значением списка является сам список; если контекст не требует списочного значения, то возвращается последний элемент списка (аналогично операции запятая в других языках программирования). Например, оператор

@people = ('Анна', 'Борис', 'Виктор');

присвоит переменной @people массив из трех элементов, тогда как оператор

$people = ('Анна', 'Борис', 'Виктор');

присвоит переменной $people строку 'Виктор'.

PERL допускает использование запятой после последнего элемента списка, например:

@people = (
  'Анна',
  'Борис',
  'Виктор',
);

Если элементы списка сами являются списками, то они разворачиваются в единый список. Например, два следующих оператора эквивалентны:

@newpeople = (@people, 'Георгий');
@newpeople = ('Анна', 'Борис', 'Виктор', 'Георгий');

Пустой список задается выражением (). Если все элементы списка являются строками, не содержащими пробелов (т. е. словами), то можно использовать конструкцию qw/слово слово.../, где вместо дробной черты допустим любой символ-разделитель или парные разделители: (), [], {}, <>. Примеры:

@people = ('Анна', 'Борис', 'Виктор');
@people = qw/Анна Борис Виктор/;
@people = qw[Анна Борис Виктор];

Списки могут использоваться не только в правой, но и в левой части оператора присваивания, если все элементы такого списка являются переменными:

($x, $y, $z) = (1, 2, 3);

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

($x, undef, $z) = (1, 2, 3);

присвоит переменной $x значение 1 и переменной $z значение 3.

Оператор присваивания списков возвращает длину присваиваемого списка. В следующем примере

$a = (($x, $y) = (1, 2, 3));

переменная $a получит значение 3.

Последним элементом списка в левой части оператор присваивания может быть массив или ассоциативный массив:

($girl, @guys) = ('Анна', 'Борис', 'Виктор', 'Георгий');

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

PERL поддерживает сокращенную форму списков, состоящих из последовательных значений, вида (значение..значение). Например, список (1..4) эквивалентен списку (1, 2, 3, 4), а список ('abc'..'abe') — списку ('abc', 'abd', 'abe').

6.2.6. Массивы

Массивы — это упорядоченные наборы значений, которые доступны по своему порядковому номеру. Элементы массива нумеруются с нуля, отрицательный номер элемента означает, что он отсчитывается от конца массива (элемент с номером -1 соответствует последнему элементу массива). Для доступа к элементу массива @array с номером n используется конструкция $array[n]:

@numbers = (1, 2, 3, 4, 5);
print $numbers[0];  # 1
print $numbers[1];  # 2
print $numbers[-1]; # 5

С каждым массивом @array связана переменная $#array, которую иногда не совсем точно называют длиной массива. На самом деле, она равна номеру последнего элемента массива. Мы можем не только читать значение этой переменной, но и изменять его, тем самым изменяя фактическую длину массива. Примеры:

@numbers = (1, 2, 3, 4, 5);
print $#numbers;  # 4
$#numbers = 2;    # @numbers = (1, 2, 3)
$#numbers = 4;    # @numbers = (1, 2, 3, undef, undef)

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

@array = ();
$#array = -1;

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

@array = ();
$array[3] = 3; # (undef, undef, undef, 3)

Преобразование массива в скаляр возвращает длину массива, т. е. scalar(@array) = $#array + 1.

Мы можем извлекать не только значения отдельных элементов массива, но и его подмассивы. Эта операция называется вырезкой (slice) и состоит в одновременном применении заданной операции к элементам массива, номера которых заданы списком. Пример:

@people = ('Анна', 'Борис', 'Виктор', 'Георгий');
print @people[1, 3];           # ('Борис', 'Георгий')
print @people[1..2];           # ('Борис', 'Виктор')
($him, $her) = @people[-1..0]; # $him = 'Георгий', $her = 'Анна'
@people[2..4] = qw/Валентин Геннадий Дмитрий/;
# теперь @people равен ('Анна', 'Борис', 'Валентин', 'Геннадий', 'Дмитрий')

Для проверки понимания изложенного ответьте на вопрос: сколько элементов в массиве (1)[1, 0]? Правильный ответ: два (undef и 1).

6.2.7. Ассоциативные массивы

Ассоциативный массив — это неупорядоченный набор пар (ключ, значение), которые доступны по ключу. Для доступа к элементу массива %hash с ключом key используется конструкция $hash{key}. Существует два способа инициализации ассоциативного массива. Первый состоит в присвоении ему списка вида (ключ1, значение1, … ключn, значениеn), например:

%fruits = ("зеленый", "яблоко", "оранжевый", "апельсин", "желтый", "банан");
print $fruits{"желтый"};

Эта программа выведет на экран слово банан. Второй способ инициализации ассоциативного массива использует операцию =>:

%fruits = (красный => "яблоко", оранжевый => "апельсин", желтый => "банан");

Обратите внимание, что названия ключей здесь не заключены в кавычки. Дело в том, операция => по умолчанию считает, что ее левый операнд является строкой. Однако, если название ключа не является единым словом, нам придется использовать кавычки:

%fruits = ("красно-зеленый" => "яблоко", оранжевый => "апельсин", желтый => "банан");

Для создания пустого ассоциативного массива используется пустой список (). Если мы хотим заранее задать размер массива, то можем использовать функцию keys:

%colors = ();
keys(%colors) = 1000;

Размер ассоциативного массива всегда является степенью числа 2, поэтому фактический размер массива %colors будет равен 1024.

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

%colors = (red => 0xff0000, blue => 0x0000ff, green => 0x008000);
$colors{'white'} = 0xffffff;
@colors{'black', 'silver','gray'} = (0x000000, 0xc0c0c0, 0x808080);

Эти конструкции требуют пояснения. Фигурные скобки здесь говорят о том, что мы обращаемся к ассоциативному массиву %colors, а символы % и @ указывают, что мы заносим в него скалярное значение и список соответственно.

В скалярном контексте ассоциативный массив возвращает строку вида "m/n", где m — количество заполненных пар, а n — количество выделенных пар в массиве. Поэтому мы можем использовать конструкцию if (%colors) … для проверки пустоты ассоциативного массива (пустой массив вернет строку "0/n", которая преобразуется в число 0).

6.2.8. Ссылки

Ссылка — это указатель на переменную. PERL обеспечивает три способа создания ссылок. Первый способ состоит в применении к переменной операции \:

$sref = \$scalar; # ссылка на скаляр
$aref = \@array;  # ссылка на массив
$href = \%hash;   # ссылка на ассоциативный массив

Применение операции \ к списку возвращает массив ссылок, например оператор

@list = \($a, @b, %c);

эквивалентен оператору

@list = (\$a, \@b, \%c);

В частности, \(@array) возвращает массив ссылок на элементы @array. Аналогично и \(%hash) вернет массив ссылок на ключи и значения %hash с одним нюансом: возвращаются ссылки не на ключи исходного ассоциативного массива, а на их копии.

Второй способ позволяет нам создавать ссылки на безымянные объекты. Ссылка на безымянный скаляр также создается операцией \:

$nref = \10;    # ссылка на число
$sref = \"\n";  # ссылка на строку

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

$aref = [1, 2, 3];
$href = {red => 0xff0000, blue => 0x0000ff, green => 0x008000};

Еще один способ создания ссылок имеет синтаксис *name{THING}, где name — имя переменной, а THING — название ее типа:

$sref = *x{SCALAR}; # ссылка на скаляр $x
$aref = *x{ARRAY};  # ссылка на массив @x
$href = *x{HASH};   # ссылка на ассоциативный массив %x

Если переменной с заданным именем и заданного типа нет, то эта конструкция возвращает undef. Смысл конструкции *name описан в п. 6.2.10, возможные значения THING — в п. 6.7.1.2.

Доступ к объекту, на который указывает ссылка $ref (разадресация ссылки) производится согласно следующему правилу: имя объекта эквивалентно выражению {$ref}. Это правило легко запомнить, но полученные с его помощью конструкции читать нелегко. Поэтому PERL допускает несколько сокращений, позволяющих обращаться к элементам разадресуемых объектов проще. Пусть, например,

$s = "Проверка";
$ps = \$s;
@a = (1, 2, 3);
$pa = \@a;
%h = {red => 0xff0000, blue => 0x0000ff, green => 0x008000};
$ph = \%h;

Тогда следующие выражения эквивалентны:

Исходный объект Полная форма Сокращения
$s ${$ps} $$ps
@a @{$pa} @$pa
$a[1] ${$pa}[1] $pa->[1], $$pa[1]
%h %{$ph} %$ph
$h{'red'} ${$ph}{'red'} $ph->{'red'}, $$ph{'red'}

Теперь мы можем привести пример использования ссылок. Рассмотрим следующий оператор:

@a = ([1, 2, 3], [4, 5, 6], [7, 8, 9]);

Он присваивает переменной @a массив, состоящий из трех ссылок на безымянные массивы. Фактически мы получили двумерный массив, к элементам которого можно обращаться так: $a[строка]->[столбец]. PERL позволяет нам опускать стрелку между индексами массива, т. е. обращение к элементу может иметь вид $a[строка][столбец], подобно обращению к элементам двумерных массивов в других языках программирования.

6.2.9. Символические ссылки

Ссылки, рассмотренные в предыдущем разделе, выглядят вполне традиционно для программиста, знакомого с языками C/C++, Pascal и т. п. Однако, PERL содержит еще один вариант ссылок (т. н. символические ссылки), который ближе по возможностям к функции eval сценарных языков. Суть состоит в том, что любая скалярная переменная может интерпретироваться как указатель на переменную, имя которой она содержит. Пусть, например, переменная $name имеет строковое значение "abc". Тогда мы можем обращаться к $name как к ссылке на переменную с именем abc, например:

$$name = 1;        # $abc = 1
${$name} = 2;      # $abc = 2
${$name x 2} = 3;  # $abcabc = 3
$name->[0] = 4;    # $abc[0] = 4
@$name = ();       # @abc = ()

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

use strict 'refs';

Во вложенном блоке мы можем вновь разрешить символические ссылки директивой

no strict 'refs';

Локальные переменные, объявленные функцией my(), невидимы для символических ссылок. Например, сценарий

$ref = "value";
$value = 10;
{
  my $value = 20;
  print $$ref;
}

выведет на экран число 10, а не 20.

6.2.10. Ссылки на таблицу символов

PERL использует для хранения ссылок на записи таблицы символов внутренний тип typeglob. Для указания на него используется форма *name. Основное назначение таких ссылок — создание синонимов для записей таблицы символов. Присваивание

*this = *that;

делает $this синонимом для $that, @this синонимом для @that, %this синонимом для %that и &this синонимом для &that. После этого любая операция с переменными this одновременно изменяет значение соответствующей переменной that, и наоборот. Пример:

$a = 0;
*b = *a;
$a = 1;
print $b; # выводит 1
$b = 2;
print $a; # выводит 2

После появления в PERLе ссылок эта конструкция стала использоваться довольно редко. Тем не менее она продолжает употребляться в более безопасной форме следующего вида:

local *my_x = \$x;

Этот оператор временно делает переменную $my_x синонимом переменной $x, но не создает синонимов для @x и т. д.

Еще одно полезное применение typeglob — это создание именованных констант, например, оператор

*PI = \3.14159265358979;

позволяет нам пользоваться значением переменной $PI, но запрещает его изменение. Подробнее о таблицах символов см. п. 6.7.1.2.

6.2.11. Описатели файлов

Описатели файлов (filehandles), строго говоря, не являются типом данных; это особый вид строковых констант. Однако, они во многом ведут себя так же, как переменные, поэтому мы описываем их в этой главе.

Описатели файлов создаются встроенной функцией open() и обеспечивают ввод-вывод файлов, например:

open INFO, "datafile" or die "Не могу открыть файл: $!";

Описатели файлов (как INFO в этом примере) принято записывать прописными буквами. PERL поддерживает три системных описателя файлов, которые создаются при запуске программы:

STDIN Стандартный файл ввода (по умолчанию, клавиатура).
STDOUT Стандартный файл вывода (по умолчанию, консоль; в Веб-приложениях обычно окно обозревателя).
STDERR Стандартный файл вывода сообщений об ошибках (по умолчанию, консоль; в серверных Веб-приложениях обычно файл протокола ошибок).

Для чтения данных из файла существует специальная операция <описатель>, в скалярном контексте возвращающая очередную запись файла или undef в конце файла или при ошибке чтения. Обычно записью является строка, но мы можем изменить символ конца записи, присвоив его специальной переменной $/. В любом случае возвращаемая строка содержит в конце разделитель записей. Мы можем присвоить результат этой операции любой переменной; если же операция вызвана без присваивания, то ее результат заносится в специальную переменную $_. Следующий пример читает строки из файла MYFILE.DAT и выводит их на консоль:

open INFO, "myfile.dat" or die "Не могу открыть файл: $!";
while (<INFO>) { print; }

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

open INFO, "myfile.dat" or die "Не могу открыть файл: $!";
@f = <INFO>;
print @f;

Операция <описатель> является сокращением для readline(*описатель). Существует особая "пустая операция" <>, которая читает либо стандартный файл ввода, либо последовательно все файлы, перечисленные в командной строке. При первом вызове операции <> PERL проверяет специальный массив @ARGV, содержащий список аргументов командной строки, и, если он пуст, заносит в $ARGV[0] строку "-", т. е. указатель на STDIN. Каждый последующий вызов <> возвращает очередную запись текущего файла, указанного в командной строке; если файл считан полностью, то окрывается следующий файл, указанный в командной строке, и возвращается его первая запись. Для проверки того, что все файлы считаны, используется встроенная функция eof().

Для вывода данных в файл обычно используется функция print(), например:

print INFO "Моя строка";

Встроенные функции работы с файлами подробно описаны в гл. 6.11.