Como obter hashes de arrays em Perl?
-
09-06-2019 - |
Pergunta
Quero escrever uma pequena função "DBQuery" em perl para que possa ter one-liners que enviem uma instrução SQL e recebam de volta uma matriz de hashes, ou seja,um conjunto de registros.No entanto, estou tendo um problema com a sintaxe Perl (e provavelmente algum problema estranho de ponteiro/referência) que está me impedindo de empacotar as informações do hash que estou obtendo do banco de dados.O código de exemplo abaixo demonstra o problema.
Posso obter os dados "Jim" de um hash dentro de um array com esta sintaxe:
print $records[$index]{'firstName'}
retorna "Jim"
mas se eu copiar primeiro o registro hash na matriz para sua própria variável hash, estranhamente não poderei mais acessar os dados nesse hash:
%row = $records[$index];
$row{'firstName'};
retorna "" (em branco)
Aqui está o código de exemplo completo mostrando o problema.Qualquer ajuda é apreciada:
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";
}
Solução
A estrutura de dados aninhada contém um hash referência, não um hash.
# 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";
Se alguma vez lhe for apresentada uma estrutura de dados Perl profunda, você poderá lucrar imprimindo-a usando Dados::Dumper para imprimi-lo em formato legível por humanos (e analisável por Perl).
Outras dicas
A matriz de hashes na verdade não contém hashes, mas sim um referências para um hash.Está linha:
%row = $records[$index];
atribui% linha com uma entrada.A chave é o escalar:
{'id' => 1, 'firstName' => 'Jim'},
Que é uma referência ao hash, enquanto o valor está em branco.
O que você realmente quer fazer é isto:
$row = $records[$index];
$row->{'firstName'};
se não:
$row = %{$records[$index];}
$row{'firstName'};
Outros comentaram sobre hashes versus hashrefs.Outra coisa que acho que deveria ser mencionada é a sua função DBQuery - parece que você está tentando fazer algo que já está embutido no DBI?Se entendi sua pergunta corretamente, você está tentando replicar algo como selectall_arrayref:
Este método utilitário combina "prepare", "execute" e "fetchall_arrayref" em uma única chamada.Ele retorna uma referência a um array contendo uma referência a um array (ou hash, veja abaixo) para cada linha de dados buscada.
Para complementar as lindas respostas acima, deixe-me acrescentar que você deve sempre, sempre, sempre (sim, três "sempre") usar "use warnings" no topo do seu código.Se você tivesse feito isso, teria recebido o aviso "Referência encontrada onde a lista de tamanho par é esperada na -e linha 1".
o que você realmente tem em seu array é um hashref, não um hash.Se você não entende esse conceito, provavelmente vale a pena ler o perlref documentação.
para obter o hash que você precisa fazer
my %hash = %{@records[$index]};
Por exemplo.
my @records = (
{'id' => 1, 'firstName' => 'Jim'},
{'id' => 2, 'firstName' => 'Joe'}
);
my %hash = %{$records[1]};
print $hash{id}."\n";
Embora.Não sei por que você faria isso, a menos que seja para fins acadêmicos.Caso contrário, eu recomendaria fetchall_hashref/fetchall_arrayref no módulo DBI ou usar algo como Class::DBI.
Observe também que um bom idioma Perl para usar é
for my $rowHR ( @records ) { my %row = %$rowHR; #or whatever... }
para iterar pela lista.