массивы и списки, ссылающиеся на вопрос - PullRequest
4 голосов
/ 15 февраля 2011

Два вопроса относительно следующего кода:


%h1 = {
    'key1' => ( 1, 2, 3 ),
    'key2' => ( 4, 5, 6 )
    };

%h2 = {
    'key1' => [ 1, 2, 3 ],
    'key2' => [ 4, 5, 6 ]
    };

print $(@h1{'key2'})[1];

Q1: В чем разница между h1 и h2? Пожалуйста, не говорите «один хэш списков, а другой хэш массивов» ... Скорее я хочу знать, что это означает с точки зрения использования.

Q2: почему ссылка $(@h1{'key2'})[1] в операторе печати не компилируется? Это мое мнение: я хочу получить доступ к массиву / списку, соответствующему 'key2': @h1{'key2'}. Затем я хочу получить доступ к скаляру с индексом 1 в этом списке / массиве: $(@h1{'key2'})[1]. Почему это не так? Эта переменная ссылается на вещи.

Ответы [ 4 ]

14 голосов
/ 15 февраля 2011

Ни одна из этих работ не работает так, как вы думаете. используйте строгое и всегда используйте предупреждения.

%h1 = {
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
};

Вы пытаетесь присвоить хэш-функции ({} конструкция) хешу. Он преобразуется в скаляр и используется как ключ в% h1 со значением undef. Кроме того, поскольку вы используете конструкцию lists (()), она сглаживается, и вы создаете хеш:

%href = ( key1 => 1,
          2 => 3,
          key2 => 4,
          5 => 6,
        );

В последнем случае вы правильно создаете свой хэш с массивом refs (конструкция []), но вы по-прежнему назначаете хэш для href Вы хотите сделать:

%h1 = (
'key1' => [ 1, 2, 3 ],
'key2' => [ 4, 5, 6 ]
);

Это создает% h1 в контексте списка и ваши значения в скалярном контексте через ссылку.

6 голосов
/ 15 февраля 2011

Разница: они оба не правы! :)

Списки являются плоскими структурами; у вас не может быть списков списков, вы просто получаете (одномерный) список обратно.

Ссылки являются скалярами. Так что %h1 = { ... } не имеет смысла. То, что вы делаете, это просто назначаете одноэлементный список на %h1, который становится строковым и превращается в ключ. Это эквивалентно

%h1 = ( 'HASH(0x1fb872a0)' => undef );

где ключ - это строковая версия любого адреса памяти, содержащегося в этой хэш-ссылке.

Чтобы создать хэш массивов, сделайте следующее:

my %h1 = ( key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] );

Если вам нужна ссылка на хэш массивов, вы можете использовать:

my $ref = { key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] };

или

my $ref = \%h1;

Наконец, чтобы получить доступ к элементам структуры, вы можете использовать:

print $h1{key2}[1];

или

print $ref->{key2}[1];

В последнем случае мы используем оператор -> для разыменования структуры. Для последующих уровней предполагается ->, но вы также можете написать

print $ref->{key2}->[1];

если вы найдете это более понятным.

Чтобы получить полную структуру из ссылки (например, использовать keys), вам нужно использовать другую форму разыменования:

my @keys = keys %$ref;    # or more explicitly %{ $ref }

Чтобы получить полную внутреннюю структуру, это то же самое:

my @a2 = @{ $ref->{key2} };

Все это подробно описано в следующих превосходных документах Perl:

  1. Учебник по Perl
  2. Perl ссылки
  3. Поваренная книга структур данных Perl

и др.

5 голосов
/ 15 февраля 2011

Разница в том, что назначение %h1 совершенно неверно, а назначение %h2 почти правильно.

Perl использует скобки для создания списка , который может быть присвоен массиву или хешу:

@a = (1, 2, 3);
%a = (foo => 'bar', 7 => 3);

Perl использует скобки для создания списка ссылок , который может быть присвоен скаляру.

$a = [ 1, 2, 3 ];

Perl использует фигурные скобки для создания ссылки на хеш , которая может быть присвоена скаляру.

$a = { key1 => 1, key2 => 2 };

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

Имея это в виду, давайте рассмотрим ваши примеры:

%h1 = { ... };

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

$scalar = { ... };
%h1 = ( "$scalar" => undef );

поэтому %h1 содержит один ключ с уродливым именем, например HASH(0x54321098), вместо того, что вы имеете в виду. Вместо этого скажите

%h1 = ( ... )

Двигаемся дальше,

%h1 = (
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
);

также не делает то, что выглядит так, как вы хотите. В этом назначении есть списки, а не ссылки на списки, и еще одна вещь, о которой следует помнить, это то, что Perl «выравнивает» списки. Если вы думаете, что => просто как причудливый синоним запятой (что почти верно), то вы увидите, что это назначение эквивалентно либо:

%h1 = ( 'key1', 1, 2, 3, 'key2', 4, 5, 6 );

или

%h1 = ( 'key1' => 1,
        2 => 3,
        'key2' => 4,
        5 => 6 );

создание хеш-таблицы с четырьмя парами ключ-значение, а не с двумя ожидаемыми вами.

Если мы исправим скобки вокруг %h2, то

%h2 = ( key1 => [ 1, 2, 3 ],
        key2 => [ 4, 5, 6 ] );

сделает то, что вы ожидаете. Помните, что значения хеш-таблиц должны быть скалярами, а ссылка на список является скаляром. Затем вы можете сказать что-то вроде $h2{'key1'}[1], чтобы получить отдельные элементы списка (в данном случае 2).

1 голос
/ 15 февраля 2011

Если он компилируется %h1 - это ассоциативный массив

( 'HASH=(...)' => undef )

Поскольку вы передаете ему массив reference вместо списка пар ключ-значение.

Если бы выражение для %h1 было допустимым, буквальный хэш был бы:

{ key1 => 1, 2 => 3, key2 => 4, 5 => 6 }

Точно так же, как если бы вы его создали, например:

my% h1 = (key1 => 1, 2 => 3, key2 => 4, 5 => 6);

Обрабатывает каждый список вместе, независимо от скобок.

В результате вы будетеразыменование '4' (или '1') в виде массива - конечно, в настоящее время вы пытаетесь разыменовать undef.

Но, скорее всего, при таком построении, когда вы делаете @h1{'key2'}, вы получаете список ( '4' ), который при оценке в скалярном контексте становится '1'

Даже если $h1{'key2'} указывает на массив @h1{'key2'} дает вам ( [ 4, 5, 6 ] ), а не ( 4, 5, 6 )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...