Массивы массивов, хэши хэшей и другие комплексные структуры данных строятся в Perl с помощью ссылок. Такой подход позволяет легко создавать иерархичные/разветвленные структуры, но требует аккуратности при обращении, копировании и изменении, поскольку по умолчанию запоминается именно ссылка, а не содержимое.
Изначально Perl поддерживал только плоские массивы и хэши, без вложенности. Позже появилась поддержка ссылок, что позволило строить любые комбинации: массивы массивов, хэши хэшей, структуры "дерево", "граф" и т.д.
Работа со сложными структурами требует помнить, что операции обращения, записи и копирования работают со ссылками. Ошибки часто возникают из-за путаницы между элементом и ссылкой на элемент. Это порождает многочисленные баги, например, изменение данных в одном месте отражается на всей структуре, если ссылка используется несколькими частями программы одновременно.
Для создания массива массивов:
my @matrix; for my $i (0..2) { for my $j (0..2) { $matrix[$i][$j] = $i * $j; } } print $matrix[1][2]; # 2
Для хэша хэшей:
my %data; $data{'user1'}{'name'} = 'Alex'; $data{'user1'}{'age'} = 20;
Смешанные структуры:
my %complex = ( 'list' => [1, 2, 3], 'map' => { foo => 'bar' }, );
Что будет, если попытаться присвоить один массив другому для копирования структуры?
Такое присваивание не копирует вложенные структуры, а копируются только ссылки на них (то есть происходит "поверхностное копирование").
my @a = ([1,2], [3,4]); my @b = @a; $a[0][0] = 99; printf "$b[0][0] "; # Выведет 99, поскольку @b содержит ссылки на те же массивы, что и @a
Чем отличается обращение к элементу как $array[$i] vs $array->[$i]?
Первый вариант работает, если у нас массив, второй — если у нас ссылающийся на массив скаляр. Для вложенных структур самый распространенный синтаксис — стрелочный ($foo->[0]).
Почему нельзя просто взять копию структуры через dclone в стандартном Perl?
Потому что dclone не входит в базовую поставку Perl. Для глубокого копирования сложных структур используют модуль Storable и функцию dclone:
use Storable 'dclone'; my $deep_copy = dclone(\%complex);
В проекте копируют массив массивов по обычному присваиванию (@copy = @org), а после ряда изменений вдруг замечают, что данные "оригинала" поменялись вместе с копией.
Плюсы:
Минусы:
Используют модуль Storable и функцию dclone для копирования массивов и хэшей, явно документируя это в коде и явно различая, где ссылка, а где не ссылка.
Плюсы:
Минусы: