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