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

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

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

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";

} 

6 ответов


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

# 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) форме.


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

%row = $records[$index];

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

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

, который является ссылкой на хэш, в то время как значение пустое.

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

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

или еще:

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

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

этот метод утилиты объединяет "prepare", "execute" и "fetchall_arrayref" в один вызов. Он возвращает ссылку на массив, содержащий ссылка на массив (или хэш, см. ниже) для каждой строки данных выборки.


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


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

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

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

например.

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

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

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

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


Также отметим хорошую идиому Perl для использования

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

для итерации по списку.