Как получить хэши из массивов в 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... }
для итерации по списку.