Массивы и sigil @

Разбираемся, как Perl хранит списки значений, почему один и тот же массив в разных местах кода называют то @arr, то $arr[0], и что такое срез массива.

Массив — переменная Perl, которая хранит упорядоченный список значений. Sigil массива — знак @, а обращение к отдельному элементу внутри него — снова через $.

От одного значения к списку

В прошлом уроке мы разобрали скаляры — переменные для одного значения. Но что, если нужно хранить не одно имя ученика, а список из тридцати имён целого класса? Заводить тридцать отдельных переменных $uchenik1, $uchenik2 и так далее было бы неудобно и бессмысленно. Для таких случаев в Perl есть массив — переменная, которая хранит сразу много значений по порядку, пронумерованных с нуля, как в большинстве языков программирования.

Sigil массива — знак @ (собака, at). Если вы работали с массивами в JavaScript или списками в Python, идея знакома — разница только в синтаксисе.

Объявление массива

my @uchenniki = ("Anya", "Boris", "Vera");

print "Klass: @uchenniki\n";
print "Vsego uchenikov: " . scalar(@uchenniki) . "\n";

Вывод:

Klass: Anya Boris Vera
Vsego uchenikov: 3

Разбираем построчно

Строка my @uchenniki = ("Anya", "Boris", "Vera"); объявляет массив uchenniki и заполняет его тремя строками, перечисленными в круглых скобках через запятую — такая запись в скобках называется списком (list). Обратите внимание: при объявлении используется sigil @, потому что мы работаем с переменной как с целым списком.

Дальше — интересная деталь: строка print "Klass: @uchenniki\n"; использует интерполяцию массива прямо внутри двойных кавычек, точно как со скалярами в прошлом уроке. Perl автоматически превращает массив в строку, вставляя пробел между элементами — поэтому вывод показывает все три имени через пробел.

Функция scalar(@uchenniki) заслуживает отдельного внимания: она заставляет Perl посмотреть на массив «в скалярном контексте» — и в этом контексте массив превращается не в список элементов, а в одно число: количество элементов в нём. Это первое знакомство с идеей контекста, которую подробно разберём в последнем уроке раздела — а пока достаточно запомнить, что scalar(@massiv) — стандартный способ узнать длину массива.

Обращение к элементу: sigil меняется на $

Вот что особенно сбивает с толку новичков: чтобы обратиться к одному конкретному элементу массива, sigil @ меняется на $.

my @frukty = ("Yabloko", "Grusha", "Banan");

print "Pervyy: $frukty[0]\n";
print "Posledniy: $frukty[-1]\n";

Вывод:

Pervyy: Yabloko
Posledniy: Banan

Логика такая: сам массив целиком @frukty — это список, много значений сразу, поэтому у него sigil @. А вот $frukty[0] — это уже одно конкретное значение (первый элемент, индексация начинается с нуля, как в Python или JavaScript), поэтому используется $, sigil скаляра. Это не опечатка и не исключение из правил — это последовательная логика Perl: sigil показывает не «какая это переменная», а «сколько значений вы сейчас имеете в виду» — одно или много. Индекс -1 — ещё одна удобная возможность Perl: отрицательные индексы считают элементы с конца, -1 — последний элемент, без нужды заранее знать длину массива.

Обход массива циклом foreach

Чтобы пройтись по всем элементам массива по очереди, используют цикл foreach — почти как for...of в JavaScript или простой for item in list в Python.

my @predmety = ("Matematika", "Fizika", "Informatika");

foreach my $predmet (@predmety) {
    print "Predmet: $predmet\n";
}

Вывод:

Predmet: Matematika
Predmet: Fizika
Predmet: Informatika

На каждом шаге цикла переменная $predmet (обратите внимание — скаляр, потому что на каждом конкретном шаге мы держим в руках ровно одно значение) по очереди получает каждый элемент массива @predmety. Тело цикла в фигурных скобках выполняется столько раз, сколько элементов в массиве.

Срезы массива

Срез (slice) — это способ достать сразу несколько элементов массива одной командой, а не по одному. Синтаксис снова использует sigil @, потому что результат — список, а не одно значение.

my @chisla = (10, 20, 30, 40, 50);

my @srez = @chisla[1, 2, 3];
print "Srez: @srez\n";

Вывод:

Srez: 20 30 40

Запись @chisla[1, 2, 3] достаёт сразу три элемента с индексами 1, 2 и 3 (то есть второй, третий и четвёртый по счёту, поскольку нумерация с нуля) и складывает их в новый массив @srez. Обратите внимание на sigil: квадратные скобки те же, что и при обращении к одному элементу, но sigil перед именем — @, а не $, потому что результат — список из нескольких значений, а не одно число.

Частые ошибки новичков

Самая частая ошибка — использовать sigil @ там, где нужен $, или наоборот. Например, написать @frukty[0] вместо $frukty[0] для одного элемента — Perl не выдаст явную ошибку сразу, но результат окажется не тем, что ожидалось, потому что @frukty[0] технически воспринимается как срез из одного элемента, а не как обычное скалярное значение.

Вторая ошибка — забыть, что индексация начинается с нуля. Первый элемент массива — это $arr[0], а не $arr[1], как иногда интуитивно кажется новичкам, привыкшим считать «первый, второй, третий» с единицы.

Третья ошибка — пытаться напечатать массив без интерполяции, например через одинарные кавычки: print '@frukty'; выведет буквально текст @frukty, а не значения элементов, потому что, как мы помним из прошлого урока, в одинарных кавычках интерполяция не работает.

Итоги

  • Массив хранит упорядоченный список значений, sigil массива — @.
  • Обращение к отдельному элементу массива идёт через $ и индекс в квадратных скобках: $arr[0] — первый элемент, $arr[-1] — последний.
  • scalar(@arr) возвращает количество элементов массива.
  • Срез — способ достать сразу несколько элементов через @arr[индексы], результат — тоже массив, поэтому sigil снова @.
  • Цикл foreach my $item (@arr) {...} — стандартный способ обойти все элементы массива по очереди.
Проверьте себя
1. Почему $frukty[0] использует sigil $, а не @, если переменная называется @frukty?
AЭто опечатка, на самом деле правильно @frukty[0]
BSigil показывает не имя переменной, а количество значений, которые сейчас имеются в виду: одно значение — всегда $, даже если оно взято из массива
C$ используется только для первого элемента массива, для остальных нужен @
DРазницы нет, оба варианта работают одинаково
2. Что вернёт scalar(@massiv), если массив @massiv содержит 5 элементов?
AПервый элемент массива
BПоследний элемент массива
CЧисло 5 — количество элементов массива
DСтроку со всеми элементами через запятую