Массив — это тип данных, предназначенный для хранения и обработки с помощью индекса целого множества однотипных данных. В языке Perl массивы могут хранить только скалярные данные, поэтому их часто называют массивами скаляров. Все массивы Perl одномерны, и их можно представлять себе как линейный список скаляров, называемых элементами массива, для ссылки на которые достаточно одного индекса. Массивы Perl хранят однотипные данные, как и в других языках программирования, но скаляр может быть числом или строкой. Поэтому с точки зрения других языков программирования в массивах Perl могут храниться разнотипные данные.
Все массивы Perl, включая массивы скаляров, рассматриваемые в этом разделе, и ассоциативные массивы, представленные в следующем разделе, являются действительно динамическими массивами. Они не требуют никакого предварительного объявления для выделения некоторой требуемой области памяти, а добавление и удаление их элементов осуществляется по ходу выполнения программы.
Для задания значений элементов массива можно использовать индекс или специальную синтаксическую конструкцию, называемую конструктором массива скаляров.
В программе для хранения массивов используются переменные, имена которых начинаются с символа @, за ним следует правильный идентификатор переменной. Однако чтобы воспользоваться «операцией» индексирования, которая синтаксически определяется целым числом или скалярной переменной в квадратных скобках, непосредственно следующих за идентификатором переменной массива, следует заменить символ @ на символ $. В Perl последовательно проводится политика использования первого символа в имени переменной для обозначения ее типа, а так как операция индексирования возвращает скалярное значение, то и требуется подобная замена первого символа. Отметим, что индексы массивов скаляров начинаются с нуля. Таким образом, появление в программе следующих операторов приводит к объявлению массива скаляров @array, содержащего два элемента:
Допускается использование отрицательных индексов для обращения к элементам массива в обратном порядке, однако следует учитывать, что при этом хотя бы один элемент массива должен быть определен. Индекс -1 соответствует последнему элементу массива, -2 — предпоследнему и т. д. Например, изменить значение последнего элемента массива @аrrау можно так:
Массивы в Perl являются динамическими. Добавление нового элемента автоматически увеличивает его размер, причем добавление не обязательно должно быть «непрерывным». Это означает, что в массиве можно задать какой-либо элемент с большим индексом, «пропустив» все предыдущие, и подобное действие не приведет к ошибке компиляции. Размер массива будет автоматически преобразован в соответствии с наибольшим использованным для элемента индексом, а не заданные элементы получат значения, равные пустой строке " ". Попытка использования значений таких элементов в выражениях при включенном режиме отображения предупреждающих сообщений интерпретатора (ключ -w) приведет к предупреждению об использовании неинициализированных значений элементов вида:
Use of uninitialized value in multiplication (*) at ex03-02.pl line 5.
Получить максимальный индекс инициализированного элемента массива можно с помощью специальной операции $#идентифинатор_массива;
Если необходимо получить количество элементов массива, то, естественно, следует к полученному значению добавить 1, так как индексация начинается с нуля. Эта операция, примененная к пустому массиву (как создать подобный массив, см. далее), возвращает значение -1. В следующем фрагменте программы определяется массив с инициализированными первым и последним (с индексом 5) элементами и подсчитывается количество его элементов:
Присваиванием конструкции $#идентификатор_массива числового значения можно увеличить или уменьшить размер массива скаляров. Присваивая значение большее, чем текущий максимальный размер индекса, мы просто расширяем диапазон допустимых символов. Элементы массива с новыми индексами будут существовать, но они не инициализированы. Присваивая значение меньше текущего максимального значения индекса, мы тем самым уменьшаем размер массива, уничтожая все его элементы с индексом, большим присвоенного значения:
Задание каждого элемента массива с помощью операции присваивания — достаточно утомительное занятие. В Perl существует специальная синтаксическая конструкция — конструктор массива, с помощью которой можно задать в одном операторе присваивания значения нескольких элементов. Конструктор массива представляет собой заключенный в круглые скобки список скалярных значений, разделенных запятыми: (скаляр1, скаляр2, . , скалярN)
В операторе присваивания переменной массива подобного конструктора каждый элемент списка представляет значение соответствующего элемента массива. Следующий оператор с конструктором
эквивалентен последовательности четырех операторов присваивания значений элементов массива с помощью индекса:
ВНИМАНИЕ В операторе присваивания значений элементам массива с помощью конструктора используется префикс @ в имени переменной массива, а при использовании операции индексирования - $.
Массив может состоять из неограниченного числа элементов, а может не иметь ни одного. В этом случае его называют пустым, и для задания такого массива используется пустой конструктор ( ).
Операцию индексирования можно применять и к конструктору массива. Конечно, для конструктора массива эта операция может оказаться бессмысленной — ведь конструктор появляется в операторе присваивания, и нет смысла в выделении элемента массива из конструктора, если после инициализации элементов массива к ним можно будет обращаться с использованием идентификатора переменной массива. Однако эта операция полезна при работе с некоторыми стандартными функциями Perl, возвращающими целый список значений. Например, функция stat( ) возвращает информацию о файле, дескриптор которого задан в качестве параметра этой функции, в виде списка значений его характеристик. Чтобы использовать индекс для доступа к восьмому элементу этого списка, который содержит размер файла, следует заключить в круглые скобки вызов этой функции и применить операцию индексирования:
Важно запомнить, что индекс можно применять к массивам скаляров и их конструкторам, а не к спискам. Если список не заключить в круглые скобки, то это приведет к ошибке компиляции сценария, как в следующем фрагменте программы:
В конструкторе массива в качестве элемента списка можно использовать другой конструктор, но мы не получим, как можно было бы подумать, элемент массива, являющийся массивом. Дело в том, что в этом случае все элементы списка такого «вложенного» конструктора массива будут просто вставлены как дополнительные элементы внешнего конструктора массива, увеличив количество элементов списка этого конструктора на количество элементов «вложенного» конструктора. Например, конструктор (1, (5, 6), 8) эквивалентен следующему: (1, 5, 6, 8). Если необходимо задать большой массив целых чисел, то можно в конструкторе массива использовать операцию «диапазон». Ее синтаксис: первое_число..последнее__число
Результатом выполнения операции является список целых чисел, начинающийся с первого числа и завершающийся последним числом. Если в качестве начала и конца диапазона заданы вещественные числа, то они преобразуются к целым простым отбрасыванием дробных частей. Например, данный конструктор @m = (-5.5..7.9); создаст массив, элементами которого являются следующие целые числа:
Операндами в операции «диапазон» могут быть и строковые данные, содержащие алфавитно-цифровые символы. В этом случае увеличение на единицу означает увеличение на единицу ASCII-кода символа строки. Примеры операции «диапазон» со строковыми данными показаны ниже:
Значения переменных массива, как и скалярных переменных, можно подставлять в строки, ограниченные двойными кавычками. При этом под значением переменной массива в операции ее подстановки в строку понимается список значений всех элементов массива, разделенных пробелами. Результатом выполнения следующих операторов:
Все правила определения идентификатора переменной массива после префикса @ при выполнении операции подстановки полностью совпадают с правилами определения идентификатора скалярной переменной после префикса $, за исключением того, что между префиксом и идентификатором не должно быть пробелов.
Подстановка значения переменной массива скаляров — удобный способ его распечатки. Дело в том, что если переменную массива просто передать в функцию печати print, то все значения элементов массива будут распечатаны без пробелов между ними, тогда как заключение имени массива в двойные кавычки приводит к хорошо читаемому результату. Для сравнения отобразим предыдущий массив @аrrау с помощью оператора:
Правила подстановки в строку значения элемента массива, выбранного с помощью индекса, полностью совпадают с правилами подстановки значения скалярной переменной. Это и очевидно, так как элемент массива представлен скаляром.
Однако при подстановке значения элемента массива может возникнуть одна интересная проблема. Язык Perl позволяет создавать с одним и тем же идентификатором переменные разных типов. Например, в программе могут сосуществовать $var (скалярная переменная), @var (переменная массива скаляров) и %var (переменная хэш-массива). Это связано с тем, что в механизме реализации переменных предусматривается создание трех пространств имен для переменных базовых типов: одно для скаляров, второе для массивов и третье — для хэш-массивов. Поэтому конфликта возникнуть не может. Но значение какого объекта будет подставлено в строку "$var[0]", если в программе определена и скалярная переменная $var, и массив @var?
Правильный ответ — значение элемента массива. Синтаксический анализатор будет выделять правильную лексему до тех пор, пока не встретится пробел или символ, добавление которого в уже полученную строку не приведет к созданию лексемы. А что же делать, если необходимо напечатать строку вида:
причем идентификатор массива хранится в переменной $var?
Для решения подобной и схожих проблем можно предложить три способа решения:
Таким образом, следующая последовательность операторов решит поставленную нами задачу вывода строки:
При работе с массивом иногда необходимо выделять из него некоторое подмножество элементов, которое будем называть фрагментом массива. Фрагмент может содержать как последовательные элементы массива, так и просто отдельные элементы массива. Последовательность элементов во фрагменте может быть произвольной. Для выполнения поставленной задачи язык Perl предлагает специальную синтаксическую конструкцию. Если после имени массива в квадратных скобках задать некоторый список целых чисел, представляющих индексы некоторых элементов массива, то такая конструкция и будет означать выделение фрагмента массива, состоящего из указанных элементов исходного массива. Несколько примеров создания фрагментов массива представлены ниже: