Массивы скаляров
Массив, в отличие от скалярного типа данных, представляющего единственное значение, — это тип данных, предназначенный для хранения и обработки нескольких скалярных данных, ссылаться на которые можно с помощью индекса. Все массивы Perl одномерны и их можно мыслить как некий линейный список скаляров. Для извлечения какого-либо значения, хранимого в массиве, достаточно одного индекса. В программе массив задается с помощью специальной синтаксической конструкции языка Perl, называемой конструктором массива. Он представляет собой список скалярных значений, заключенный в круглые скобки. Элементы списка отделяются друг от друга запятыми и представляют элементы массива:
(скаляр_1, скаляр_2, ... , скаляр_n)
Как и в других языках программирования, массив Perl представляет набор однотипных данных — скаляров, но скалярные данные могут быть как числовыми, так и строковыми, поэтому, с точки зрения других языков программирования, в массивах Perl хранятся смешанные данные — числа и строки. В качестве скаляра в конструкторе массива может использоваться числовой или строковый литерал или скалярная переменная, чье значение и будет являться элементом массива:
(5, "умножить на", 4) # Используются только литералы.
($first, 'равно', $second) # Используются значения скалярных переменных.
Массив может состоять из неограниченного числа элементов, а может не иметь ни одного. В таком случае его называют пустым массивом. Конструктор пустого массива — круглые скобки без содержащегося в них списка ().
Как отмечалось в начале параграфа, массив характеризуется тем, что к любому его элементу можно обратиться при помощи индекса (целого литерала или скалярной переменной, принимающей целое значение), который задается в квадратных скобках непосредственно после конструктора массива. Индексы массивов в языке Perl начинаются с о, а отрицательные индексы позволяют обратиться к элементам в обратном их заданию порядке:
(5, "умножить на", 4)[0] # Первый элемент массива: 5.
(5, "умножить на", 4)[2] # Последний элемент массива: 4.
(5, "умножить на", 4)[-1] f Последний элемент массива: 4.
(5, "умножить на", 4) [-3] # Первый элемент массива: 5.
При использовании отрицательных индексов индекс -1 соответствует последнему элементу массива, а индекс -п, где п — количество элементов массива, первому элементу массива.
Нельзя использовать индекс для извлечения элементов списка, возвращаемого некоторыми функциями Perl. Индекс можно применять только к массивам или их конструкторам, а для этого достаточно заключить список в круглые скобки. Например, конструкция stat(@m) [0] вызовет ошибку компиляции, если возвращаемым значением функции stat является список, тогда как конструкция (stat (@m)) [0] приведет к желаемому эффекту.
В качестве элемента списка в конструкторе массива можно использовать конструктор массива, но мы не получим в этом случае, как ожидает читатель, знакомый с другими языками программирования, массив массивов, т. е. многомерный массив, к элементам которого можно обратиться с помощью нескольких индексов. Дело в том, что если в качестве элемента списка в конструкторе массива используется конструктор массива, то его элементы добавляются к элементам массива, определяемого внешним конструктором, т. е. каждый его элемент становится элементом внешнего массива, увеличивая количество его элементов на количество элементов внутреннего массива. Например, массив
(1, (2, 3), 4}
эквивалентен массиву
(1, 2, 3, 4)
(О реализации многомерных массивов при помощи ссылок см. в части 9.)
В программе массивы хранятся в специальных переменных, имена которых начинаются с символа "@". Объявление переменной массива, или просто массива, чаще всего осуществляется в операторе присваивания (=), в правой части которого обычно задается конструктор массива:
Sarray = ($ml, '+', $m2, '=', $ml+$m2);
В этом примере также продемонстрировано, что в конструкторе массива можно использовать выражения, о которых речь пойдет в следующей главе.
Задать или получить значения элементов массива, хранящегося в переменной, можно и с помощью индекса. Однако "операцию" индексирования нельзя применять непосредственно к имени переменной массива, ее следует применять к переменной, в которой первый символ заменен на символ скалярной переменной $. Подобное "неудобство" связано с последовательным проведением в Perl использования первого символа переменной для указания ее типа: ведь элемент массива является ничем иным как скаляром. Примеры использования индекса с переменными массива представлены ниже:
$ml[0] = "Первый"; # Задает первый элемент массива @ml.
$ml[l] = "Второй"; # Задает второй элемент массива @ml.
@m2 = (1, 2, 3, 4, 5); # Задание массива @т2.
print @ml, "\n", $m2[0]; # Печать массива toil и
# первого элемента массива @m2.
Массивы в Perl являются динамическими. Добавление нового элемента в массив автоматически увеличивает его размер. С помощью индекса можно добавить элемент, отстоящий от последнего определенного элемента массива на любое число элементов, и это действие не приведет к ошибке. Просто все промежуточные элементы будут не определены (их значение будет равно пустой строке ""). При такой реализации массивов программисту не надо заботиться, как в других языках программирования, что индекс выйдет за размеры массива. В случае обращения к не существующему элементу массива Perl возвращает значение, равное нулевой строке.
Замечание
Если для интерпретатора peri включен режим отображения предупреждающих сообщений во время выполнения, то в случае обращения к не определенному или не существующему элементу массива будет отображаться сообщение, что значение элемента не определено.
В любой момент можно определить число элементов массива. Для этого следует воспользоваться синтаксической конструкцией
$ #имя_массива
которая возвращает максимальный индекс массива или -1, если массив не определен. Чтобы получить количество элементов массива, следует к возвращаемому значению этой конструкции добавить 1, так как индексы массивов в Perl начинаются со.
При работе с массивами самой "утомительной" процедурой может оказаться процедура присваивания значений элементам массива. Хорошо, если все необходимые данные для заполнения массива большой размерности уже существуют в каком-либо текстовом файле. Тогда можно присвоить значения элементам массива, воспользовавшись операцией чтения из внешнего файла, но об этом в следующей главе. А если необходимо в программе создать массив натуральных чисел до 1000 включительно? Неужели надо писать 1000 операторов присваивания, или организовывать цикл, в котором осуществлять соответствующие присваивания, или создавать текстовый файл, содержащий эти числа? К счастью, нет! В Perl для подобных ситуаций предусмотрена операция диапазон, которую можно использовать в конструкторе массива. Например, чтобы создать массив натуральных чисел до 1000, достаточно одного оператора:
@naturalNumbers = (1..1000);
Общий синтаксис операции диапазон следующий:
первое_число..последнее_число
Она определяет набор чисел (целых или вещественных), начинающихся с первое_число и не превосходящих последнее_число, в котором последующее больше предыдущего на единицу. Эта операция действительна не только для чисел, но и для алфавитно-цифровых строк, но в этом случае увеличение на единицу означает увеличение на единицу ASCII-кода символа строки. Ниже показаны примеры использования операции диапазон со строковыми данными:
"а".."с" i Соответствует: "а", "b", "с"
"BCY".."BDB" # Соответствует: "BCY", "BCZ", "BDA", "ВОВ"
Эта операция особенно удобна для задания целых чисел, начинающихся с нуля, например, для представления дня месяца в дате вида "01.02.2000":
@ day_ofjnonth = ("01".."31");
(Подробнее операция диапазон рассматривается в части 4.)
Переменные массива и элемент массива можно подставлять в строки, ограниченные двойными кавычками. Если интерпретатор встречает в строке переменную массива, то он вставляет в нее значения элементов массива, отделенные друг от друга пробелами. Результатом выполнения следующих операторов
@т = (1. .3);
print "Числа@{т}являются целыми";
будет строка
Числа! 2 являются целыми
Все правила определения идентификатора скалярной переменной при ее подстановке в строку переносятся и на переменную массива.
В связи с возможностью подстановки переменной массива можно указать быстрое решение проблемы распечатки содержимого массива. Дело в том, что если в операторе печати просто указать переменную массива, то его элементы выводятся сплошной строкой без пробелов между ними, что является неудобным при работе с числовыми данными. Если вставить переменную массива в строку, то при ее печати между элементами массива будут вставлены пробелы. Следующие два оператора печати
print @m, "\n"; print "@m\n";
отобразят массив @m предыдущего примера по-разному:
123
123
Подстановка в строку элемента массива с помощью индексного выражения ничем не отличается от подстановки скалярной переменной: элемент массива, полученный с помощью индекса, является скалярной величиной. Однако здесь может возникнуть одна интересная проблема, если в программе определена скалярная переменная с таким же идентификатором, что и у массива. Значение этой переменной или значение соответствующего элемента массива будет вставлено в строку? Например, если в программе определена скалярная переменная $var и массив @var (о том, почему это возможно, мы расскажем в разделе 3.5 данной главы), то значение переменной или элемента массива будет вставлено в строку "$var [0]".
Правильный ответ — значение элемента, так как при синтаксическом анализе интерпретатор будет рассматривать встретившуюся последовательность символов как лексему $var[0], а не как имя переменной $var с последующим символом "[". Если необходимо использовать значение скалярной переменной $var в строке, то можно предложить три способа решения этой проблемы:
"${var}[0.]" # Фигурные скобки ограничивают символы, рассматриваемые
# интерпретатором как единое целое с символом $. "$var\[0]"
# Обратная дробная черта ограничивает идентификатор
# переменной. "$var" .• "[0]" # Конкатенация строк (операция ".") позволяет однозначно
# интерпретировать переменную в первой строке.
Иногда для работы необходимо выделить некоторое подмножество элементов массива, которое мы будем называть фрагментом массива. Можно ее выполнить просто, но не эффективно: присвоить элементам некоторого нового массива значения соответствующих элементов старого, можно воспользоваться специальной конструкцией Perl для выделения фрагмента массива. Если после имени переменной массива в квадратных скобках задать список индексов некоторых элементов массива, то такая конструкция и будет определять фрагмент массива, причем индексы не обязательно должны идти в каком-то определенном порядке — их можно задавать произвольно. Для выделения фрагмента, состоящего из последовательно идущих элементов массива, можно использовать знакомую нам операцию диапазон. Фрагмент массива сам является массивом, и поэтому его можно использовать в правой части оператора присваивания. Несколько примеров создания фрагментов массива приведено ниже:
@т = (10..19); # Исходный массив:
# (10, 11, 12, 13, 14, 15, 16, 17, 18, 19). @т[0, 2, 4, 6, 8];
# Фрагмент 1: (10, 12, 14, 16, 18). @т[6, 4, 5, 8, 6];
# Фрагмент 2: (16, 14, 15, 18, 16). @т[2..4];
# Фрагмент 3: (12, 13, 14). @т[8, 2..4, 0];
# Фрагмент 4: (18, 12, 13, 14, 10).
При выделении фрагмента массива используется имя переменной массива, начинающейся с символа "@", тогда как при ссылке на элемент массива префикс имени переменной заменяется на символ "$". Здесь опять прослеживается последовательное использование префикса для задания типа переменной. Фрагмент массива является массивом, а потому следует использовать символ "@".