Как получить хэши из массивов в Perl?

Я хочу написать небольшую функцию "DBQuery" в perl, поэтому у меня могут быть однострочные, которые отправляют SQL-запрос и получают обратно, и массив хэшей, т.е. набор записей. Однако я столкнулся с проблемой синтаксиса Perl (и, вероятно, некоторой нечетной проблемы с указателем/ссылкой), которая мешает мне упаковывать информацию из хеша, которую я получаю из базы данных. Пример кода ниже демонстрирует проблему.

Я могу получить данные "Jim" из хэша внутри массива с помощью этого синтаксиса:

print $records[$index]{'firstName'}

возвращает "Jim"

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


    %row = $records[$index];
    $row{'firstName'};

возвращает "" (пробел)

Вот полный пример кода, показывающий проблему. Любая помощь приветствуется:


my @records = (
   {'id' => 1, 'firstName' => 'Jim'},
   {'id' => 2, 'firstName' => 'Joe'}
);
my @records2 = ();

$numberOfRecords = scalar(@records);
print "number of records: " . $numberOfRecords . "\n";
for(my $index=0; $index < $numberOfRecords; $index++) {

   #works
   print 'you can print the records like this: ' . $records[$index]{'firstName'} . "\n";

   #does NOT work
   %row = $records[$index];
   print 'but not like this: ' . $row{'firstName'} . "\n";

} 

Ответы

Ответ 1

Вложенная структура данных содержит хеш-ссылку, а не хэш.

# Will work (the -> dereferences the reference)
$row = $records[$index];
print "This will work: ", $row->{firstName}, "\n";

# This will also work, by promoting the hash reference into a hash
%row = %{ $records[$index] };
print "This will work: ", $row{firstName}, "\n";

Если вам когда-либо предоставлена ​​глубокая структура данных Perl, вы можете извлечь выгоду из ее печати с помощью Data::Dumper, чтобы напечатать ее в человеческом (и Perl-parsable).

Ответ 2

Массив хэшей на самом деле не содержит хешей, а скорее ссылки на хеш. Эта строка:

%row = $records[$index];

присваивает% row одной записью. Ключ - это скаляр:

   {'id' => 1, 'firstName' => 'Jim'},

Это ссылка на хеш, а значение пустое.

Что вы действительно хотите сделать, так это:

$row = $records[$index];
$row->{'firstName'};

или еще:

$row = %{$records[$index];}
$row{'firstName'};

Ответ 3

Другие прокомментировали хеши против хехрефов. Еще одна вещь, о которой я думаю, следует упомянуть о вашей функции DBQuery - кажется, вы пытаетесь сделать что-то, что уже встроено в DBI? Если я правильно понял ваш вопрос, вы пытаетесь воспроизвести что-то вроде selectall_arrayref:

Этот метод утилиты объединяет команды "подготовить", "выполнить" и "fetchall_arrayref" в один вызов. Он возвращает ссылку на массив, содержащий ссылку на массив (или хеш, см. Ниже) для каждой строки данных.

Ответ 4

Чтобы добавить к прекрасным ответам выше, позвольте мне добавить, что вы всегда, всегда, всегда (да, три "всегда" ) используют "использовать предупреждения" в верхней части вашего кода. Если бы вы это сделали, вы получили предупреждение "Ссылка, найденная там, где ожидался список размерных размеров на -e строке 1".

Ответ 5

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

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

my %hash = %{@records[$index]};

Eg.

my @records = (
     {'id' => 1, 'firstName' => 'Jim'}, 
     {'id' => 2, 'firstName' => 'Joe'}
  );

  my %hash = %{$records[1]};

  print $hash{id}."\n";

Хотя. Я не уверен, почему вы хотели бы это сделать, если только не для академических целей. В противном случае я бы рекомендовал fetchall_hashref/fetchall_arrayref в модуле DBI или использовать что-то вроде Class:: DBI.

Ответ 6

Также обратите внимание, что хорошая идиома perl для использования -

for my $rowHR ( @records ) {
   my %row = %$rowHR; 
   #or whatever...
}

чтобы перебирать список.