Reputation: 31
I am just wondering If I can get some help with dereferencing in Perl?
I have a while loop where I am querying a DB and iterating over what I get back. I then write the data I need into a hash and push the hash into an array. This is all forming part of a JSON string.
However, I can only push the reference to the hash and not the hash itself (I've tried all sorts of things), meaning if the loop goes (e.g.) 3 times, I get the same thing appearing 3 times in the JSON I am trying to PUT.
Here is the code:
my $json = new JSON::XS;
my $json_text = JSON::XS->new->decode (shift->content);
my $sig_num = 0;
my %sig_hash;
<MySQL Stuff -removed for readability>
while($query_handle->fetch())
{
$sig_num++;
$sig_hash{position} = 'below';
$sig_hash{signature_text} = $sig;
$sig_hash{signature_name} = 'Signature '.$sig_num;
$sig_hash{signature_default} = JSON::XS::true;
push (@{$json_text->{data}->{mail}->{signatures}}, \%sig_hash);
}
return $json_text;
Thanks for any help!
Upvotes: 3
Views: 257
Reputation: 42411
The hash ref that you're pushing on to the array is scoped at the outer level (outside the while
loop). This means there is only one hash being referenced: you are pushing references to the same hash on to the array multiple times. I assume you want a fresh hash for each iteration of the loop. If so, declare my %sig_hash
inside the loop rather than outside.
You can experiment with this script to see the difference. First run it as it is; then move the my %h
outside the loop and run it again.
my @data;
for (1..3){
my %h; # New hash for each iteration of the loop.
$h{a} = 10 * $_;
$h{b} = 20 * $_;
push @data, \%h;
}
use Data::Dumper;
print Dumper(\@data);
Upvotes: 6
Reputation: 126722
I suggest you use an autovivified anonymous hash delared, as FMc explains, within the while
loop. The code becomes simpler that way, and becomes
my $json = new JSON::XS;
my $json_text = JSON::XS->new->decode(shift->content);
my $sig_num = 0;
while ($query_handle->fetch) {
my $sig_hash;
$sig_hash->{position} = 'below';
$sig_hash->{signature_text} = $sig;
$sig_hash->{signature_name} = "Signature ".++$sig_num;
$sig_hash->{signature_default} = JSON::XS::true;
push @{$json_text->{data}{mail}{signatures}}, $sig_hash;
}
return $json_text;
or if you prefer you can build and push an anonymous hash directly onto the stack without assigning it to a variable
my $json = new JSON::XS;
my $json_text = JSON::XS->new->decode(shift->content);
my $sig_num = 0;
while ($query_handle->fetch) {
push @{$json_text->{data}{mail}{signatures}}, {
position => 'below',
signature_text => $sig,
signature_name => "Signature ".++$sig_num,
signature_default => JSON::XS::true,
};
}
return $json_text;
Upvotes: 1