2011-12-22 4 views
1

Я однажды прочитал следующий пример о «массиве массивов». АОА представляет собой двумерный массивО доступе к массиву массивов

Следующий фрагмент кода испрашивается печатать все дело с рефов

for $aref (@AoA) { 
    print "\t [ @$aref ],\n"; 
} 

А следующий сегмент кода испрашивается для печати все это с индексами

for $i (0 .. $#AoA) { 
    print "\t [ @{$AoA[$i]} ],\n"; 
} 

Что здесь стоит $ aref? Как понять определение @$aref и @{$AoA[$i]}? Благодарю.

+4

Пожалуйста, прочтите [perldoc perldata] (http://perldoc.perl.org/perldata.html) и [perldoc perlref] (http://perldoc.perl.org/perlref.html), и все станет ясно! – Ether

ответ

5

$aref означает «ссылка на массив», то есть ссылку для массива.

my $my_aref = \@somearray; 

Вы можете создать массив из ссылки на массив со следующим синтаксисом:

@{$my_aref} 

@{$my_aref}является@somearray. (Это не копия, это действительно тот же массив.)

Во втором примере $AoA[$i] является ссылкой на массив, и вы разыгрываете его с тем же синтаксисом: @{$AoA[$i]}.

См. perlreftut для получения дополнительных пояснений и примеров.

1

«массив массивов» на самом деле не массив массивов. Это больше массив ссылок на массивы. Каждый элемент в базовом массиве является ссылкой на другой массив. Таким образом, если вы хотите циклически перемещаться по элементам в базовом массиве, вы получаете обратные ссылки массива. Это то, что присваивается $aref в первом цикле. Затем они отбрасываются с предварительным ожиданием с помощью символа @, поэтому @$aref - это массив, на который ссылается ссылка массива $aref.

То же самое относится ко второму циклу. $AoA[$i] - это $i-й элемент массива @AoA, который является ссылкой на массив. Де-ссылкой на него, предварительно ожидая его с символом @ (и добавив {} для ясности и, возможно, для приоритета) означает, что @{$AoA[$i]} - это массив, на который ссылается ссылка на массив $AoA[$i].

1

У Perl нет многомерных массивов. Один массив помещает массивы в другие массивы для достижения того же результата.

Ну, почти. Значения массивов (и хэшей) являются скалярами, поэтому нельзя помещать массив в другой массив. Вместо того, чтобы вместо этого указывать ссылку на массив.

Другими словами, «массив массивов» не подходит для «массива ссылок на массивы». Каждое значение @AoA является ссылкой на другой массив, учитывая «иллюзию» двумерного массива.


Ссылка взята из использования [ ] или ее эквивалента. [ ] создает анонимный массив, затем создает ссылку на этот массив, а затем возвращает ссылку. Вот откуда берется ссылка.

Обычные способы построения ССХ:

my @AoA = (
    [ 'a', 'b', 'c' ], 
    [ 'd', 'e', 'f' ], 
); 

my @AoA; 
push @AoA, [ 'a', 'b', 'c' ]; 
push @AoA, [ 'd', 'e', 'f' ]; 

my @AoA; 
$AoA[$y][$x] = $n; 

Имейте в виду, что

$AoA[$y][$x] = $n; 

коротка для

$AoA[$y]->[$x] = $n; 

и это эквивалентно следующим благодаря autovivification:

($AoA[$y] //= [])->[$x] = $n; 
1

Вся тайна с многомерными структурами в 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]}; 
} 

И это все, что есть к этому!

Смежные вопросы