Ссылки: как сделать массив массивов

Представь, что тебе нужно хранить таблицу — например, оценки нескольких учеников по нескольким предметам. Обычный массив Perl хранит только плоский список значений: числа, строки. А если нужно хранить массив внутри массива? Вот тут и появляются ссылки.

Ссылка (reference) — это переменная, которая хранит не сами данные, а адрес, где эти данные лежат в памяти. Звучит абстрактно, но на практике это просто способ «упаковать» массив или хеш в единое значение, которое можно передать дальше, положить в другую структуру или вернуть из функции.

Зачем это нужно

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

Решение — не класть массив целиком, а положить ссылку на него. Ссылка — это одно скалярное значение (как число или строка), поэтому она отлично помещается в элемент другого массива. Так и получается массив массивов, хеш массивов и любая другая вложенная структура.

Оператор \ — создаём ссылку

Чтобы получить ссылку на переменную, перед ней ставится обратный слэш \. Это работает для массивов, хешей и скаляров одинаково:

my @numbers = (10, 20, 30);
my $ref_to_array = \@numbers;

print $ref_to_array;

Вывод:

ARRAY(0x55d3f2a1b2c0)

Видно, что переменная $ref_to_array хранит не список чисел, а нечто вроде «адреса» — тип ARRAY и шестнадцатеричный идентификатор ячейки памяти. Это и есть ссылка: компактное значение, которое указывает на настоящий массив @numbers, лежащий где-то ещё.

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

Оператор -> — разыменование

Получить обратно доступ к данным по ссылке называется разыменованием (dereferencing). Самый читаемый способ — стрелка ->:

my @numbers = (10, 20, 30);
my $ref_to_array = \@numbers;

print $ref_to_array->[0];
print "\n";
print $ref_to_array->[2];

Вывод:

10
30

Синтаксис $ref_to_array->[0] означает «пойди по ссылке $ref_to_array и возьми элемент с индексом 0 из массива, на который она указывает». Квадратные скобки после стрелки — знак того, что мы обращаемся к массиву. Для хешей вместо скобок используются фигурные — об этом в следующем уроке.

Собираем массив массивов

Теперь главный трюк: элементами обычного массива могут быть ссылки на другие массивы. Так получается «массив массивов» — по сути, таблица.

my @row1 = (1, 2, 3);
my @row2 = (4, 5, 6);
my @row3 = (7, 8, 9);

my @matrix = (\@row1, \@row2, \@row3);

print $matrix[1]->[2];

Вывод:

6

Разберём построчно. Сначала создаём три обычных массива-строки. Потом собираем @matrix — это массив, но его элементы не числа, а ссылки на @row1, @row2, @row3. Обращение $matrix[1] берёт второй элемент @matrix (индексация с нуля) — это ссылка на @row2. А ->[2] уже разыменовывает её и берёт третий элемент этого массива, то есть 6.

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

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

print $matrix[2]->[0];

Вывод:

7

Квадратные скобки [1, 2, 3] в этом контексте — не индексация, а создание анонимного массива и сразу же ссылки на него. Это самый распространённый способ описывать таблицы и вложенные списки в реальном коде — компактно и наглядно.

Стрелка необязательна между скобками

Perl разрешает опускать стрелку между соседними квадратными или фигурными скобками — код $matrix[2]->[0] и $matrix[2][0] работают одинаково:

my @matrix = ( [1, 2, 3], [4, 5, 6] );

print $matrix[1][2];

Вывод:

6

Первая стрелка (сразу после имени переменной) тоже часто опускается на практике, но между двумя разными «уровнями» вложенности — например, между ссылкой на массив внутри хеша и следующим уровнем — её лучше сохранять для читаемости, особенно пока структура ещё не привычна.

Частые ошибки

Первая ошибка — забыть про сигил $ при обращении к элементу. Даже если структура называется @matrix, конкретный элемент — это скаляр, поэтому обращение начинается с $matrix[...], а не @matrix[...] (последнее означает совсем другое — срез массива).

Вторая — попытка напечатать ссылку и удивление, что вместо чисел вывелось что-то вроде ARRAY(0x...). Это не ошибка программы, а напоминание: ссылку нужно сначала разыменовать через ->, чтобы добраться до реальных данных.

Третья — путаница между \@array (ссылка на существующий именованный массив) и [1, 2, 3] (создание нового анонимного массива с сразу готовой ссылкой на него). Оба варианта дают ссылку, но используются в разных ситуациях: первый — когда массив уже где-то объявлен, второй — когда структура собирается «на лету».

Итоги

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

Проверьте себя
1. Что нужно, чтобы получить доступ к элементу массива, на который указывает ссылка $ref?
AПросто написать $ref[0]
BРазыменовать через $ref->[0]
CИспользовать @ref[0]
DСсылки нельзя разыменовать, только вывести целиком
2. Какой код создаёт массив массивов из двух строк [1, 2] и [3, 4]?
Amy @m = (1, 2, 3, 4);
Bmy @m = ([1, 2], [3, 4]);
Cmy @m = \(1, 2, 3, 4);
Dmy @m = {1, 2, 3, 4};