Вся загадка с многомерными структурами в 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' ]);
Тад!Это массив массивов.
Теперь мы можем вернуться назад.Чтобы получить доступ к значениям внутри этого массива, мы можем сделать
for my $scalar ( @aoa ) {
print @$scalar; # prints 123abcxyz
}
На этот раз я использовал другое имя переменной, просто чтобы сделать точку.Этот цикл берет каждое значение из @aoa
- которое все еще является только скалярным значением - разыменовывает его как массив и печатает его.
Или мы можем получить доступ к @aoa
через его индексы
for my $i ( 0 .. $#aoa ) {
print @{$aoa[$i]};
}
И это все, что нужно!