What is the difference between referencing a variable using \ and {}, [] in perl?

below code works fine, but if i replace push @array,{%hash}

with push @array,\%hash

then it is not. Can someone please help me understand the difference. I believe it {%hash}

refers to anonymous hash. Does this mean that anonymous hash lives longer than a reference to a named hash ( \%hash

).

use strict;
use warnings;
use Data::Dumper;
my @array;
my %hash;
%hash = ('a' => 1,
         'b' => 2,
         'c' => 3,);

push @array,{%hash};

%hash = ('e' => 1,
         'f' => 2,
         'd' => 3,);

push @array,{%hash};

print Dumper \@array;

      

Output

$VAR1 = [
          {
            'c' => 3,
            'a' => 1,
            'b' => 2
          },
          {
            'e' => 1,
            'd' => 3,
            'f' => 2
          }
        ];

      

UPDATE Below is the actual code I am working on. I think that in this case, copy of the link is the only possible solution I believe. Please correct me if I am wrong.

use Data::Dumper;
use strict;
use warnings;

my %csv_data;
my %temp_hash;
my @cols_of_interest = qw(dev_file test_file diff_file status);
<DATA>; #Skipping the header
while (my $row = <DATA>) {
    chomp $row;
    my @array = split /,/,$row;
    @temp_hash{@cols_of_interest} = @array[3..$#array]; 
    push @{$csv_data{$array[0]}{$array[1] . ':' . $array[2]}},{%temp_hash};
}
print Dumper \%csv_data;

__DATA__
dom,type,id,dev_file,test_file,diff_file,status
A,alpha,1234,dev_file_1234_1.txt,test_file_1234_1.txt,diff_file_1234_1.txt,pass
A,alpha,1234,dev_file_1234_2.txt,test_file_1234_2.txt,diff_file_1234_2.txt,fail
A,alpha,1234,dev_file_1234_3.txt,test_file_1234_3.txt,diff_file_1234_3.txt,pass
B,beta,4567,dev_file_4567_1.txt,test_file_4567_1.txt,diff_file_4567_1.txt,pass
B,beta,4567,dev_file_4567_2.txt,test_file_4567_2.txt,diff_file_4567_2.txt,fail
C,gamma,3435,dev_file_3435_1.txt,test_file_3435_1.txt,diff_file_3435_1.txt,pass
D,hexa,6768,dev_file_6768_1.txt,test_file_6768_1.txt,diff_file_6768_1.txt,fail

      

+3


source to share


2 answers


Both \%hash

and {%hash}

create links, but they refer to two different things.

\%hash

is a link to %hash

. If dereferenced, its values ​​will change with the values ​​in %hash

.

{%hash}

creates a new anonymous hash reference from the values ​​in %hash

. He makes a copy . This is the easiest way to create a shallow copy of a Perl data structure. If you change %hash

, this copy will not be affected.




How long a variable lives has nothing to do with what type of the variable or how it was created. Only scope is suitable for this . References in Perl are a special case here because there is an internal ref counter that keeps track of references to a value, so that it is kept alive if there is a reference somewhere, even if it is out of scope. This is why it works:

sub frobnicate {
    my %hash = ( foo => 'bar' );
    return \%hash;
}

      

If you want to disable the reference from the initial value, you need to turn it into a weak reference via weaken

from Scalar :: Util . Thus, the number of references will not depend on it, but it will still be associated with the value, while the copy will not.

See perlref and perlreftut for more information on links. This question is about link counts. A description for this is also available in the chapter Link Count and Mortality in perlguts .

+13


source


You cannot compare \

with {}

and []

as they don't do the same thing at all.

{ LIST }

not suitable for my %anon = LIST; \%anon

[ LIST ]

not suitable for my @anon = LIST; \@anon


Perhaps you wanted to compare

  • & # xA0;

    my %hash = ...;
    push @a, \%hash;
    
          

  • & # xA0;

    push @a, { ... };
    
          

  • & # xA0;

    my %hash = ...;
    push @a, { %hash };
    
          

The first snippet puts a link to %hash

in @a

. Presumably this can be found in a loop. As long as the loop is found my %hash

, a link to the new hash will be placed @a

each time.

The second snippet does the same, just using an anonymous hash.

The third snippet makes a copy %hash

and places a link to that copy in @a

. This creates an impression of wastefulness and is therefore discouraged. (It's actually not that wasteful because it allows for %hash

reuse.)




You can also write your code

# In reality, the two blocks below are probably the body of one sub or one loop.

{
   my %hash = (
      a => 1,
      b => 2,
      c => 3,
   );

   push @a, \%hash;
}

{
   my %hash = (
      d => 3,
      e => 1,
      f => 2,
   );

   push @a, \%hash;
}

      

or

push @a, {
   a => 1,
   b => 2,
   c => 3,
};

push @a, {
   d => 3,
   e => 1,
   f => 2,
};

      


my @cols_of_interest = qw( dev_file test_file diff_file status );

my %csv_data;
if (defined( my $row = <DATA> )) {
    chomp $row;
    my @cols = split(/,/, $row);

    my %cols_of_interest = map { $_ => 1 } @cols_of_interest;
    my @cols_to_delete = grep { !$cols_of_interest{$_} } @cols;

    while ( my $row = <DATA> ) {
        chomp $row;
        my %row; @row{@cols} = split(/,/, $row);
        delete @row{@cols_to_delete};
        push @{ $csv_data{ $row{dev_file} }{ "$row{test_file}:$row{diff_file}" } }, \%row;
    }
}

      

Better yet, let's use the correct CSV parser.

use Text::CSV_XS qw( );

my @cols_of_interest = qw( dev_file test_file diff_file status );

my $csv = Text::CSV_XS->new({
    auto_diag => 2,
    binary    => 1,
});

my @cols = $csv->header(\*DATA);

my %cols_of_interest = map { $_ => 1 } @cols_of_interest;
my @cols_to_delete = grep { !$cols_of_interest{$_} } @cols;

my %csv_data;
while ( my $row = $csv->getline_hr(\*DATA) ) {
    delete @$row{@cols_to_delete};
    push @{ $csv_data{ $row->{dev_file} }{ "$row->{test_file}:$row->{diff_file}" } }, $row;
}

      

+3


source







All Articles