Sam Bessey
Sam Bessey

Reputation: 31

Perl - De- Referencing a Hash

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

Answers (2)

FMc
FMc

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

Borodin
Borodin

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

Related Questions