Как получить хеши из массивов в Perl? - PullRequest
13 голосов
/ 09 сентября 2008

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

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

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

возвращает "Джим"

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


    %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 ]

23 голосов
/ 09 сентября 2008

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

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

5 голосов
/ 09 сентября 2008

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

%row = $records[$index];

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

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

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

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

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

или еще:

$row = %{$records[$index];}
$row{'firstName'};
4 голосов
/ 09 сентября 2008

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

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

3 голосов
/ 10 сентября 2008

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

1 голос
/ 09 сентября 2008

то, что у вас есть в массиве, - это хеш, а не хеш. Если вы не понимаете эту концепцию, возможно, стоит прочитать документацию 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, либо использовать что-то вроде Class :: DBI.

0 голосов
/ 16 сентября 2008

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

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

для просмотра списка.

...