Вся тайна с многомерными структурами в perl довольно легко понять, как только вы осознаете, что есть только три типа переменных. Скалары, массивы и хеши.
- Скаляр - это единственное значение, оно может содержать практически все, но только одно в то время.
- Массив содержит ряд скалярных значений, упорядоченных по фиксированному числовому индексу .
- Хэш содержит скалярные значения, индексированные ключами из строк.
И все массивы, хеши или скаляры действуют таким образом. Многомерные массивы ничем не отличаются от одного измерения.
Это также выражено в очень кратко perldata:
Все данные в Perl является скаляр, массив скаляров, или хэш скаляров. Скаляр может содержать одно единственное значение в любом из трех различных вариантов: число, строка или ссылку. В общем случае преобразование является прозрачным. Хотя скаляр может не содержать непосредственно несколько значений, он может содержать ссылку на массив или хэш, который, в свою очередь, содержит несколько значений.
Например:
my @array = (1, 2, 3);
Здесь $array[0]
содержит 1, $array[1]
содержит 2 и т.д. Так же, как и следовало ожидать.
my @aoa = ([ 1, 2, 3 ], [ 'a', 'b', 'c' ]);
Здесь $array[0]
содержит ссылку на массив. Если вы распечатаете его, он скажет что-то вроде ARRAY(0x398a84)
. Не волнуйся! Это все еще скалярное значение. Откуда нам это знать? Поскольку массивы могут содержать только скалярные значения.
Когда мы делаем что-то вроде
for $aref (@AoA) {
print $aref; # prints ARRAY(0x398a84) or similar
}
Это ничем не отличается от этого
for $number (@array) {
print $number;
}
$aref
и $number
скалярные значения. Все идет нормально.Найдите момент и заблокируйте это знание: Массивы могут содержать только скалярные значения.
Теперь следующая часть просто зная, как справиться со ссылками. Это задокументировано в perlref и perlreftut.
Ссылка является скалярным значением. Это адрес места в памяти. Это местоположение содержит некоторые данные. Чтобы получить доступ к фактическим данным, нам нужно разыменовать ссылку.
В качестве простого примера:
my @data = (1, 2, 3);
my $aref = \@data; # The backslash in front of the sigil creates a reference
print $aref; # print something like ARRAY(0xa4b6a4)
print @$aref; # prints 123
Добавление сигила перед ссылкой говорит Perl разыменовать значение скалярного в тип данных сигил представляет. В этом случае массив. Если вы выбираете неправильный сигил для типа задания, Perl выдаст сообщение об ошибке, таких как:
Not a HASH reference
В примере выше, у нас есть ссылка на конкретное, названное место. Оба значения @$aref
и @data
имеют одинаковые значения. Если мы изменим значение в одном, оба будут затронуты, потому что адрес в ячейке памяти идентичен. Давайте попробуем:
my @data = (1, 2, 3);
my $aref = \@data;
$$aref[1] = 'a'; # dereference to a scalar value by $ sigil
# $aref->[1] = 'a' # does the same thing, a different way
print @data; # prints 1a3
print @$aref; # prints 1a3
У нас также могут быть анонимные данные. Если бы мы были заинтересованы только в создании массива массивов, мы не должны были бы никакого интереса к @data
, и может пропустить его, делая это:
my $aref = [ 1, 2, 3 ];
В скобки списка номеров создать анонимный массив. $aref
все еще содержит один и тот же тип данных: Ссылка. Но в этом случае $aref
- единственный способ доступа к данным, содержащимся в памяти. Теперь, давайте создадим еще некоторые скалярные значения, как это:
my $aref1 = [ 1, 2, 3 ];
my $aref2 = [ 'a', 'b', 'c' ];
my $aref3 = [ 'x', 'y', 'z' ];
Теперь у нас есть три скалярные переменные, которые содержат ссылки на анонимные массивы. Что, если мы поместим их в массив?
my @aoa = ($aref1, $aref2, $aref3);
Если бы мы хотим получить доступ к $aref1
, мы могли бы сделать print @$aref1
, но мы могли бы также сделать
print @{$aoa[0]};
В этом случае необходимо использовать расширенную форму разыменования: @{ ... }
. Поскольку perl не любит двусмысленность, нам нужно различать @{$aoa[0]}
(возьмите ссылку в $aoa[0]
и разыщите как массив) и @{$aoa}[0]
(возьмите ссылку в $aoa
и разыщите как массив и возьмите это первое значение массива).
Выше мы могли бы использовать @{$aref}
, так как он идентичен @$aref
.
Итак, если нас интересует только массив массивов, нас тоже не интересуют сканеры $aref1
. Поэтому давайте сократим их из процесса:
my @aoa = ([ 1, 2, 3 ], [ 'a', 'b', 'c' ], [ 'x', 'y', 'z' ]);
Tada! Это массив массивов.
Теперь мы можем отступить. Для того, чтобы получить доступ к значениям внутри этого массива, мы можем сделать
for my $scalar (@aoa) {
print @$scalar; # prints 123abcxyz
}
На этот раз я использовал другое имя переменной, просто чтобы сделать точку. Этот цикл принимает каждое значение от @aoa
, которое по-прежнему является только скалярным значением - разыгрывает его как массив и печатает его.
Или мы можем получить доступ к @aoa
через свои индексы
for my $i (0 .. $#aoa) {
print @{$aoa[$i]};
}
И это все, что есть к этому!
Пожалуйста, прочтите [perldoc perldata] (http://perldoc.perl.org/perldata.html) и [perldoc perlref] (http://perldoc.perl.org/perlref.html), и все станет ясно! – Ether